zoukankan      html  css  js  c++  java
  • Swift

    在Swift开发中,如果我们需要保持客服端和服务器的长连接进行双向的数据通信,使用socket是一种很好的解决方案。

    下面通过一个聊天室的样例来演示socket通信,这里我们使用了一个封装好的socket库(SwiftSocket)。

    功能如下:
    1,程序包含服务端和客服端,这里为便于调试把服务端和客服端都做到一个应用中
    2,程序启动时,自动初始化启动服务端,并在后台开启一个线程等待客服端连接
    3,同时,客户端初始化完毕后会与服务端进行连接,同时也在后台开启一个线程等待接收服务端发送的消息
    4,连接成功后,自动生成一个随机的用户名(如“游客232”)并发送消息告诉服务器这个用户信息
    5,点击界面的“发送消息”按钮,则会发送聊天消息到服务端,服务端收到后会把聊天消息发给所有的客服端。客服端收到后显示在对话列表中

    注意:消息传递过程使用的json格式数据。
    目前这个demo里消息种类有用户登录消息,聊天消息,后面还可以加上用户退出消息等。为了在接收到消息以后,能判断是要执行什么命令。我们创 建消息体的时候使用字典NSDictionary(其中cmd表示命令类型,content表示内容体),发送消息时把字典转成json串传递,当另一端 接收的时候,又把json串还原成字典再执行响应的动作。

    效果图如下:
       

    代码如下:
    --- ViewController.swift 主页面 ---
    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    import UIKit
     
    class ViewController: UIViewController {
         
        //消息输入框
        @IBOutlet weak var textFiled: UITextField!
        //消息输出列表
        @IBOutlet weak var textView: UITextView!
         
        //socket服务端封装类对象
        var socketServer:MyTcpSocketServer?
        //socket客户端类对象
        var socketClient:TCPClient?
         
        override func viewDidLoad() {
            super.viewDidLoad()
             
            //启动服务器
            socketServer = MyTcpSocketServer()
            socketServer?.start()
             
            //初始化客户端,并连接服务器
            processClientSocket()
        }
         
        //初始化客户端,并连接服务器
        func processClientSocket(){
            socketClient=TCPClient(addr: "localhost", port: 8080)
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
                () -> Void in
                 
                //用于读取并解析服务端发来的消息
                func readmsg()->NSDictionary?{
                    //read 4 byte int as type
                    if let data=self.socketClient!.read(4){
                        if data.count==4{
                            var ndata=NSData(bytes: data, length: data.count)
                            var len:Int32=0
                            ndata.getBytes(&len, length: data.count)
                            if let buff=self.socketClient!.read(Int(len)){
                                var msgd:NSData=NSData(bytes: buff, length: buff.count)
                                var msgi:NSDictionary=NSJSONSerialization.JSONObjectWithData(
                                    msgd,
                                    options: .MutableContainers, error: nil) as! NSDictionary
                                return msgi
                            }
                        }
                    }
                    return nil
                }
                 
                //连接服务器
                var (success,msg)=self.socketClient!.connect(timeout: 5)
                if success{
                    dispatch_async(dispatch_get_main_queue(), {
                        self.alert("connect success", after: {
                        })
                    })
                     
                    //发送用户名给服务器(这里使用随机生成的)
                    var msgtosend=["cmd":"nickname","nickname":"游客(Int(arc4random()%1000))"]
                    self.sendMessage(msgtosend)
                     
                    //不断接收服务器发来的消息
                    while true{
                        if let msg=readmsg(){
                            dispatch_async(dispatch_get_main_queue(), {
                                self.processMessage(msg)
                            })
                        }else{
                            dispatch_async(dispatch_get_main_queue(), {
                                //self.disconnect()
                            })
                            break
                        }
                    }
                }else{
                    dispatch_async(dispatch_get_main_queue(), {
                        self.alert(msg,after: {
                        })
                    })
                }
            })
        }
         
        //“发送消息”按钮点击
        @IBAction func sendMsg(sender: AnyObject) {
            var content=textFiled.text
            var message=["cmd":"msg","content":content]
            self.sendMessage(message)
            textFiled.text=nil
        }
         
        //发送消息
        func sendMessage(msgtosend:NSDictionary){
            var msgdata=NSJSONSerialization.dataWithJSONObject(msgtosend,
                options: NSJSONWritingOptions.PrettyPrinted, error: nil)
            var len:Int32=Int32(msgdata!.length)
            var data:NSMutableData=NSMutableData(bytes: &len, length: 4)
            self.socketClient!.send(data: data)
            self.socketClient!.send(data:msgdata!)
        }
         
        //处理服务器返回的消息
        func processMessage(msg:NSDictionary){
            var cmd:String=msg["cmd"] as! String
            switch(cmd){
            case "msg":
                self.textView.text = self.textView.text +
                    (msg["from"] as! String) + ": " + (msg["content"] as! String) + " "
            default:
                println(msg)
            }
        }
         
        //弹出消息框
        func alert(msg:String,after:()->(Void)){
            var alertview=UIAlertView(title: "", message: msg, delegate: nil,
                cancelButtonTitle: nil)
            alertview.show()
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3), dispatch_get_main_queue(),{
                alertview.dismissWithClickedButtonIndex(0, animated: true)
                after()
            })
        }
         
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }
    --- MyTcpSocketServer.swift 服务端 ---
    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    import UIKit
     
    //服务器端口
    var serverport = 8080
     
    //客户端管理类(便于服务端管理所有连接的客户端)
    class ChatUser:NSObject{
        var tcpClient:TCPClient?
        var username:String=""
        var socketServer:MyTcpSocketServer?
         
        //解析收到的消息
        func readMsg()->NSDictionary?{
            //read 4 byte int as type
            if let data=self.tcpClient!.read(4){
                if data.count==4{
                    var ndata=NSData(bytes: data, length: data.count)
                    var len:Int32=0
                    ndata.getBytes(&len, length: data.count)
                    if let buff=self.tcpClient!.read(Int(len)){
                        var msgd:NSData=NSData(bytes: buff, length: buff.count)
                        var msgi:NSDictionary=NSJSONSerialization.JSONObjectWithData(msgd,
                            options: .MutableContainers, error: nil) as! NSDictionary
                        return msgi
                    }
                }
            }
            return nil
        }
         
        //循环接收消息
        func messageloop(){
            while true{
                if let msg=self.readMsg(){
                    self.processMsg(msg)
                }else{
                    self.removeme()
                    break
                }
            }
        }
         
        //处理收到的消息
        func processMsg(msg:NSDictionary){
            if msg["cmd"] as! String=="nickname"{
                self.username=msg["nickname"] as! String
            }
            self.socketServer!.processUserMsg(user: self, msg: msg)
        }
         
        //发送消息
        func sendMsg(msg:NSDictionary){
            var jsondata=NSJSONSerialization.dataWithJSONObject(msg, options:
                NSJSONWritingOptions.PrettyPrinted, error: nil)
            var len:Int32=Int32(jsondata!.length)
            var data:NSMutableData=NSMutableData(bytes: &len, length: 4)
            self.tcpClient!.send(data: data)
            self.tcpClient!.send(data: jsondata!)
        }
         
        //移除该客户端
        func removeme(){
            self.socketServer!.removeUser(self)
        }
         
        //关闭连接
        func kill(){
            self.tcpClient!.close()
        }
    }
     
    //服务端类
    class MyTcpSocketServer: NSObject {
        var clients:[ChatUser]=[]
        var server:TCPServer=TCPServer(addr: "127.0.0.1", port: serverport)
        var serverRuning:Bool=false
         
        //启动服务
        func start() {
            server.listen()
            self.serverRuning=true
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
                while self.serverRuning{
                    var client=self.server.accept()
                    if let c=client{
                        dispatch_async(
                            dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
                            self.handleClient(c)
                        })
                    }
                }
            })
            self.log("server started...")
        }
         
        //停止服务
        func stop() {
            self.serverRuning=false
            self.server.close()
            //forth close all client socket
            for c:ChatUser in self.clients{
                c.kill()
            }
            self.log("server stoped...")
        }
     
        //处理连接的客户端
        func handleClient(c:TCPClient){
            self.log("new client from:"+c.addr)
            var u=ChatUser()
            u.tcpClient=c
            clients.append(u)
            u.socketServer=self
            u.messageloop()
        }
         
        //处理各消息命令
        func processUserMsg(user u:ChatUser,msg m:NSDictionary){
            self.log("(u.username)[(u.tcpClient!.addr)]cmd:"+(m["cmd"] as! String))
            //boardcast message
            var msgtosend=[String:String]()
            var cmd = m["cmd"] as! String
            if cmd=="nickname"{
                msgtosend["cmd"]="join"
                msgtosend["nickname"]=u.username
                msgtosend["addr"]=u.tcpClient!.addr
            }else if(cmd=="msg"){
                msgtosend["cmd"]="msg"
                msgtosend["from"]=u.username
                msgtosend["content"]=(m["content"] as! String)
            }else if(cmd=="leave"){
                msgtosend["cmd"]="leave"
                msgtosend["nickname"]=u.username
                msgtosend["addr"]=u.tcpClient!.addr
            }
            for user:ChatUser in self.clients{
                //if u~=user{
                user.sendMsg(msgtosend)
                //}
            }
        }
         
        //移除用户
        func removeUser(u:ChatUser){
            self.log("remove user(u.tcpClient!.addr)")
            if let possibleIndex=find(self.clients, u){
                self.clients.removeAtIndex(possibleIndex)
                self.processUserMsg(user: u, msg: ["cmd":"leave"])
            }
        }
         
        //日志打印
        func log(msg:String){
            println(msg)
        }
    }


    源码下载:SocketTest.zip

  • 相关阅读:
    PTA 乙级 1032 挖掘机技术哪家强 (20分) C++
    Jmeter接口测试之MD5函数使用
    charles基础理论一
    Jmeter接口测试之函数和cookies
    appium+robotframework之权限设置
    appium+robotframework之context问题解决
    jmeter接口测试之断言持续时间
    Appium+robotframework 自动化之软键盘的调起(文本框无法输入值)
    Jmeter接口测试之测试计划和线程组的关系
    Jmeter接口测试之用户定义变量
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4843325.html
Copyright © 2011-2022 走看看