はじめに
SwiftとTypeScriptをTCP通信する要件があったので、サンプル実装しました!!
TCP通信とは?
TCPは、2つのプログラムを接続して、データをやり取りするための通信方法です。
今回だと、
Swift
⇄ TCP
TypeScript
という接続を作ります。
TCPの特徴はシンプルです。
- 一度接続すると、その接続を使ってデータを送り続けられる
- Swift → TypeScript、TypeScript → Swiftの両方向に送れる
- 文字列だけでなく、JSONや画像などのバイナリも送れる
- TCP自体は「メッセージ」ではなく、バイト列のストリームとして扱う
今回はまず、
Swift → "こんにちは" → TypeScript
という最小の通信だけを試します。
| Swift | TypeScript | |
|---|---|---|
| 役割 | クライアント | サーバー |
| API | NWConnection |
node:net |
| 動作 | 接続 → 送信 → 切断 | 待受 → 受信 |
今回は次のルールだけ決めます。
127.0.0.1:9000
UTF-8
1メッセージ = 1行(末尾に \n)
今回の成果物
ディレクトリ
typescript_swift_study/
├── typescript/
│ ├── package.json
│ ├── tsconfig.json
│ └── src/
│ └── server.ts
└── swift/
├── Package.swift
└── Sources/
└── SocketClient/
└── main.swift
前提:
macOS
Node.js
Swift 5.9+
通信の流れ
TypeScript
Node.js標準のnetでTCPサーバーを作ります。
import net from "node:net";
const HOST = "127.0.0.1";
const PORT = 9000;
const server = net.createServer((socket) => {
console.log("connected");
socket.setEncoding("utf8");
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk;
while (buffer.includes("\n")) {
const index = buffer.indexOf("\n");
const message = buffer.slice(0, index);
buffer = buffer.slice(index + 1);
console.log("received:", message);
}
});
socket.on("end", () => {
console.log("disconnected");
});
});
server.listen(PORT, HOST, () => {
console.log(`listening on ${HOST}:${PORT}`);
});
TCPは「メッセージ」ではなくバイト列のストリームです。
そのため今回は、
こんにちは\n
のように\nを区切りとして使います。
Swift
Network.frameworkのNWConnectionを使います。
import Foundation
import Network
let connection = NWConnection(
host: "127.0.0.1",
port: 9000,
using: .tcp
)
let queue = DispatchQueue(label: "socket")
let semaphore = DispatchSemaphore(value: 0)
connection.stateUpdateHandler = { state in
switch state {
case .ready:
let payload = CommandLine.arguments.dropFirst().first ?? "こんにちは"
let data = Data((payload + "\n").utf8)
connection.send(
content: data,
completion: .contentProcessed { error in
if let error {
print("send failed:", error)
} else {
print("sent:", payload)
}
connection.cancel()
semaphore.signal()
}
)
case .failed(let error):
print("connect failed:", error)
semaphore.signal()
default:
break
}
}
connection.start(queue: queue)
semaphore.wait()
やっていることはこれだけです。
NWConnection作成
↓
TCP接続
↓
ready
↓
"こんにちは\n" を送信
↓
切断
実行
まずTypeScriptを起動します。
cd typescript
npm install
npm start
listening on 127.0.0.1:9000
別ターミナルからSwiftを実行します。
cd swift
swift run SocketClient こんにちは
Swift:
sent: こんにちは
TypeScript:
connected
received: こんにちは
disconnected
これで、
Swift
↓ TCP
TypeScript
の最小通信ができました。
今回やったこと
Swift
↓
TCP接続
↓
UTF-8文字列を送信
↓
TypeScriptで受信
↓
切断
次はこの接続をそのまま使って、
TypeScript → Swift
echo
JSON
常時接続
画像
へ広げられます。
