Swift - 使用vapor socks库进行socket通信(基于TCP、UDP协议)
本文介绍另一个 socket 库:vapor 的 socks 库。个人感觉这个用起来更加简单方便,而且原生就有 receiveAll 方法,方便我们发送和接收不定长消息。
一、安装配置
(1)从 Github 主页下载代码:https://github.com/vapor/socks
(2)将下载下来的 Socks 文件夹添加到项目中。

二、基于TCP协议的socket通信
1,效果图
(1)程序运行后会启动一个 tcp 服务器,监听 8080 端口。
(2)同时还会初始化一个 tcp 客户端。在输入框中填写内容后,点击“发送”按钮即可将消息发送到服务端(本文样例就是自己发给自己)。
(3)服务端接收到消息后会显示在界面上,同时接收到的消息又返回客户端。
(4)客户端收到反馈消息后同样会将其显示在界面上。

2,样例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | import UIKit class ViewController : UIViewController { //发送消息输入框 @IBOutlet weak var textField: UITextField ! //用于显示接收到的消息 @IBOutlet weak var textView: UITextView ! //TCP服务端 var server: SynchronousTCPServer ! //TCP客户端 lazy var client: TCPClient ? = { //初始化客户端 let address = InternetAddress (hostname: "127.0.0.1" , port: 8080) do { return try TCPClient (address: address) } catch { print ( "Error \(error)" ) return nil } }() override func viewDidLoad() { super .viewDidLoad() //启动服务器 startServer() } //启动服务器 func startServer() { //在后台线程中启动服务器 DispatchQueue .global(qos: .background).async { do { //初始化服务器 self .server = try SynchronousTCPServer (port: 8080) //在界面上显示启动信息 DispatchQueue .main.async { let hostname = self .server.address.hostname let address = self .server.address.addressFamily let port = self .server.address.port self .textView.text = "服务器启动,监听:" + "\"\(hostname)\" (\(address)) \(port)\n" } //接收并处理客户端连接 try self .server.startWithHandler { (client) in self .handleClient(client: client) } } catch { print ( "Error \(error)" ) } } } //处理连接的客户端 func handleClient(client: TCPClient ){ do { while true { //获取客户端发送过来的消息:[UInt8]类型 let data = try client.receiveAll() //将接收到的消息转成String类型 let str = try data.toString() //将这个String消息显示到界面上 DispatchQueue .main.async { self .textView.text = self .textView.text + "服务端接收到消息: \(str)\n" } //将接收到的消息又发回客户端 try client.send(bytes: data) //try client.close() //关闭与客户端链接 } } catch { print ( "Error \(error)" ) } } //发送消息 @IBAction func sendMessage(_ sender: Any ) { do { let message = self .textField.text if message != nil && message != "" { try client?.send(bytes: message!.toBytes()) let str = try client!.receiveAll().toString() //将服务端返回的消息显示在界面上 self .textView.text = self .textView.text + "客户端接收到反馈: \(str)\n" //try client.close() //关闭客户端与服务端链接 //清空输入框 self .textField.text = "" } } catch { print ( "Error \(error)" ) } } override func didReceiveMemoryWarning() { super .didReceiveMemoryWarning() } } |

三、基于UDP协议的socket通信
由于 UDP 不像 TCP 那样需要三次握手,所以不需要建立连接通道,也没有断开连接之说,发送完了也就完了。因此代码简单许多。1,效果图
(1)功能和上面的大体一样。程序运行后会启动一个 udp 服务器,监听 8080 端口。(2)同时还会初始化一个 udp 客户端。在输入框中填写内容后,点击“发送”按钮即可将消息发送到服务端(本文样例就是自己发给自己)。
(3)服务端接收到消息后会显示在界面上,同时接收到的消息又返回客户端。
(4)客户端收到反馈消息后同样会将其显示在界面上。

2,样例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import UIKit class ViewController : UIViewController { //发送消息输入框 @IBOutlet weak var textField: UITextField ! //用于显示接收到的消息 @IBOutlet weak var textView: UITextView ! //UDP服务端 var server: SynchronousUDPServer ! //UDP客户端 lazy var client: UDPClient ? = { //初始化客户端 let address = InternetAddress (hostname: "127.0.0.1" , port: 8080) do { return try UDPClient (address: address) } catch { print ( "Error \(error)" ) return nil } }() override func viewDidLoad() { super .viewDidLoad() //启动服务器 startServer() } //启动服务器 func startServer() { //在后台线程中启动服务器 DispatchQueue .global(qos: .background).async { do { //初始化服务器 self .server = try SynchronousUDPServer (port: 8080) //在界面上显示启动信息 DispatchQueue .main.async { let hostname = self .server.address.hostname let address = self .server.address.addressFamily let port = self .server.address.port self .textView.text = "服务器启动,监听:" + "\"\(hostname)\" (\(address)) \(port)\n" } //接收并处理客户端消息 try self .server.startWithHandler(handler: { (received:[ UInt8 ], client: UDPClient ) in self .handleClient(received: received, client: client) }) } catch { print ( "Error \(error)" ) } } } //处理接收到的客户端消息 func handleClient(received:[ UInt8 ], client: UDPClient ){ do { //将接收到的消息转成String类型 let str = try received.toString() //将这个String消息显示到界面上 DispatchQueue .main.async { self .textView.text = self .textView.text + "服务端接收到消息: \(str)\n" } //将接收到的消息又发回客户端 try client.send(bytes: received) } catch { print ( "Error \(error)" ) } } //发送消息 @IBAction func sendMessage(_ sender: Any ) { do { let message = self .textField.text if message != nil && message != "" { try client?.send(bytes: message!.toBytes()) //获取服务端返回的消息 let str = try client!.receive().data.toString() //将服务端返回的消息显示在界面上 self .textView.text = self .textView.text + "客户端接收到反馈: \(str)\n" //清空输入框 self .textField.text = "" } } catch { print ( "Error \(error)" ) } } override func didReceiveMemoryWarning() { super .didReceiveMemoryWarning() } } |
航哥,请问接收到服务端发来的消息后是不是应该有个响应的代理方法呢,不然当有了新消息之后怎么及时接收消息更新UI呢
航哥您好 ,我想问一下类似微信的即时通讯对话框,对方发消息我的客户端怎么知道有没有新消息呢,通过轮询可以吗,后台每秒刷新一次看有没有新消息,有的话再更新UI?轮询的话是不是很不合理?
航哥,你好!我的程序有一个要往服务器发图片的功能,格式是:头+图片+尾
let startData = msgtosend.data(using: String.Encoding.utf8, allowLossyConversion: false)!//头部字符串转data
let endData = end.data(using: String.Encoding.utf8, allowLossyConversion: false)!//尾部字符串转data
let mutableData = NSMutableData()
mutableData.append(startData)//头
mutableData.append(imageData)//图片
mutableData.append(endData)//尾
try client?.send(bytes: message!.toBytes())你的这个发送方法的参数是[UInt8]的,怎么把mutableData转成[UInt8]呢,
我试过先把mutableData转成data在转字符串在转[UInt8],但是发到服务器的时候已经错了,是不是转的太多转坏了
求航哥帮忙解答,谢谢
航哥,这个支持IPV6吗?谢谢!