分类 socket 下的文章

使用GCDAsyncSocket基本使用

//
//  ViewController.swift
//  socket练习-聊天室客户端
//
//  Created by admin on 16/3/16.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,GCDAsyncSocketDelegate {

    @IBOutlet weak var messageTableView: UITableView!
    @IBOutlet weak var messageTextField: UITextField!
    @IBOutlet weak var messageView: UIView!
    var socket:GCDAsyncSocket?
    override func viewDidLoad() {
        super.viewDidLoad()
        self.messageTableView.delegate = self
        self.messageTableView.dataSource = self
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardFrameChange:"), name: UIKeyboardWillChangeFrameNotification, object: nil)
        self.view.bringSubviewToFront(self.messageView)
    }
    func keyboardFrameChange(not:NSNotification)
    {
        /**
        {
        UIKeyboardAnimationCurveUserInfoKey = 7;
        UIKeyboardAnimationDurationUserInfoKey = "0.25";
        UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}";
        UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 796}";
        UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 538}";
        UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 667}, {375, 258}}";
        UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 409}, {375, 258}}";
        UIKeyboardIsLocalUserInfoKey = 1;
        }
        */
        let begingFrame:CGPoint = (not.userInfo!["UIKeyboardCenterBeginUserInfoKey"]?.CGPointValue)!
        let endFrame:CGPoint = (not.userInfo!["UIKeyboardCenterEndUserInfoKey"]?.CGPointValue)!
        if (begingFrame.y - endFrame.y) > 0
        {
            // 弹出
            self.messageView.transform = CGAffineTransformMakeTranslation(0, -(begingFrame.y - endFrame.y))
        }
        else
        {
            self.messageView.transform = CGAffineTransformIdentity
        }
    }
    deinit
    {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    // 建立连接
    @IBAction func connection(sender: UIBarButtonItem) {
        //ios里实现sokcet的连接,使用C语言

        // 1.与服务器通过三次握手建立连接
        let host:CFString = "127.0.0.1"
        let port:UInt16 = 52013

        self.socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_global_queue(0, 0))

        let res = try? self.socket?.connectToHost(host as String, onPort: port)
        if res != nil
        {
            print("ok")
        }
        else
        {
            print("error")
        }
    }
    // 连接完成
    func socket(sock: GCDAsyncSocket!, didConnectToHost host: String!, port: UInt16) {
        print("连接")
    }
    func socketDidDisconnect(sock: GCDAsyncSocket!, withError err: NSError!) {
        if err == nil
        {
            print("断开连接")
        }
        else
        {
            print("发生错误了。。。。")
        }
    }
    // 写入数据,需要读取下,不然后面不能进行
    func socket(sock: GCDAsyncSocket!, didWriteDataWithTag tag: Int) {
        socket?.readDataWithTimeout(-1, tag: tag)
    }
    // 读取数据
    func socket(sock: GCDAsyncSocket!, didReadData data: NSData!, withTag tag: Int) {
        let res = NSString(data: data, encoding: NSUTF8StringEncoding)
        if tag == 8888
        {
            print(res)
        }
        else if tag == 6888
        {
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                self.messages.append(res!)
                self.messageTableView.reloadData()
            })
        }
    }
    @IBAction func login(sender: UIBarButtonItem) {
        let str = "login:zhangsan"
        self.socket?.writeData(str.dataUsingEncoding(NSUTF8StringEncoding), withTimeout: -1, tag: 8888)
    }
    var messages:[NSString] = []
    @IBAction func sendMessage(sender: UITextField) {
        let message:NSString = sender.text!
        if(message.length > 0)
        {
            self.socket?.writeData("message:\(message)".dataUsingEncoding(NSUTF8StringEncoding), withTimeout: -1, tag: 6888)
        }
    }
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return self.messages.count
    }
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("MessageCell")
        cell?.textLabel?.text = self.messages[indexPath.row] as String
        return cell!
    }
}

socket服务端(GCDAsyncSocket)

main.swift

//
//  main.swift
//  socket服务器
//
//  Created by admin on 16/3/16.
//  Copyright © 2016年 jin. All rights reserved.
//

import Foundation
let server = Server()
server.start(52013)
NSRunLoop.currentRunLoop().run()

Server.swift

//
//  Server.swift
//  socket服务器
//
//  Created by admin on 16/3/16.
//  Copyright © 2016年 jin. All rights reserved.
//


class Server: NSObject,GCDAsyncSocketDelegate {
    var serverSocket:GCDAsyncSocket?
    var clientSockets:[GCDAsyncSocket] = []
    override init()
    {
        super.init()
        self.serverSocket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
    }
    // 开启服务器
    func start(port:UInt16)
    {
        let res = try? self.serverSocket?.acceptOnPort(port)
        if res != nil
        {
            print("ok")
        }
        else
        {
            print("error")
        }
    }
    // 当有新的客户端时会调用这个方法,注意要把客户端socket保存起来,不然客户端连上立马就退出了
    func socket(sock: GCDAsyncSocket!, didAcceptNewSocket newSocket: GCDAsyncSocket!) {
        // 保存起来
        self.clientSockets.append(newSocket)
        // 客户端先读取下数据,不然无法服务器无法接受客户端的数据
        newSocket.readDataWithTimeout(-1, buffer: nil, bufferOffset: 0, tag: self.clientSockets.count)
    }
    // 接受客户端的数据,当客户端又数据的时候会调用这个方法
    func socket(sock: GCDAsyncSocket!, didReadData data: NSData!, withTag tag: Int) {
        // 转换二进制数据
        var str = NSString(data: data, encoding: NSUTF8StringEncoding)
        // 去掉换行和回车
        str = str?.stringByReplacingOccurrencesOfString("\n", withString: "")
        str = str?.stringByReplacingOccurrencesOfString("\r", withString: "")
        // 把字符串按照 : 符号分隔成数组
        let strArr = str?.componentsSeparatedByString(":")
        // 初始化返回值字符串
        var outputStr:NSString = "不能识别"
        // 对不同类型的消息进行处理
        if strArr?.count > 1
        {
            switch(strArr![0])
            {
            case "message":
                outputStr = "\(strArr![0])说\(strArr![1])"
                break
            case "login":
                outputStr = "\(strArr![1])登录成功"
                break
            default:
                break
            }
        }
        if strArr![0] == "quit"
        {
            // 关闭连接
            sock.disconnect()
            // 从socket数组中移除
            self.clientSockets.removeAtIndex(self.clientSockets.indexOf(sock)!)
        }
        outputStr = "\(outputStr)\n"
        // 往客户端写入数据
        sock.writeData(outputStr.dataUsingEncoding(NSUTF8StringEncoding), withTimeout: -1, tag: tag)
    }
    // 在服务器写数据的时候会调用,这里必须实现并且read下数据,不然上面的方法就只能执行一次
    func socket(sock: GCDAsyncSocket!, didWriteDataWithTag tag: Int) {
        sock.readDataWithTimeout(-1, tag: tag)
    }
}

iOS中socket的基本使用

//
//  ViewController.swift
//  socket练习-聊天室客户端
//
//  Created by admin on 16/3/16.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController,NSStreamDelegate,UITableViewDelegate,UITableViewDataSource {

    @IBOutlet weak var messageTableView: UITableView!
    @IBOutlet weak var messageTextField: UITextField!
    var inputStream:NSInputStream?
    var outputStream:NSOutputStream!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.messageTableView.delegate = self
        self.messageTableView.dataSource = self
    }
    // 建立连接
    @IBAction func connection(sender: UIBarButtonItem) {
        //ios里实现sokcet的连接,使用C语言

        // 1.与服务器通过三次握手建立连接
        let host:CFString = "127.0.0.1"
        let port:UInt32 = 52013

        // 2.定义输入输出流

        var readStream:Unmanaged<CFReadStream>?
        var writeStream:Unmanaged<CFWriteStream>?

        // 3.分配输入输出流的内存空间
//        CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);

        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readStream, &writeStream)

        // 4.把C语言的输入输出流转成OC对象

        self.inputStream = readStream?.takeRetainedValue()
        self.outputStream = writeStream!.takeUnretainedValue()

//        _inputStream = (__bridge NSInputStream *)readStream;
//        _outputSteam = (__bridge NSOutputStream *)(writeStream);
//        

        // 5.设置代理,监听数据接收的状态
        self.inputStream?.delegate = self
        self.outputStream?.delegate = self
        // 把输入输入流添加到主运行循环(RunLoop)
        // 主运行循环是监听网络状态
        self.inputStream?.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
        self.outputStream?.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)

        // 6.打开输入输出流
        self.inputStream?.open()
        self.outputStream.open()
    }
    @IBAction func login(sender: UIBarButtonItem) {
        let str = "login:zhangsan"
        self.sendData(str)
        let res = self.readData()
        print(res)
    }
    var messages:[NSString] = []
    @IBAction func sendMessage(sender: UITextField) {
        let message:NSString = sender.text!
        if(message.length > 0)
        {
            self.sendData("message:\(message)")
            let res = self.readData()
            self.messages.append(res)
            self.messageTableView.reloadData()
        }
    }
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return self.messages.count
    }
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("MessageCell")
        cell?.textLabel?.text = self.messages[indexPath.row] as String
        return cell!
    }
    // 代理方法,在不同的状态会调用这个方法
    func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
        switch(eventCode)
        {
        case NSStreamEvent.OpenCompleted:
                print("建立连接成功,形成输入输出流通道")
            break
        case NSStreamEvent.HasBytesAvailable:
            print("可以读取数据")
            break
        case NSStreamEvent.HasSpaceAvailable:
            print("可以发送数据")
            break
        case NSStreamEvent.ErrorOccurred:
            print("发生错误")
            break
        case NSStreamEvent.EndEncountered:
            print("正常断开连接")
            // 关闭输入输出流,并从主运行循环中移除
            self.inputStream?.close()
            self.inputStream?.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
            self.outputStream.close()
            self.outputStream?.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
            break
        default:
            break
        }
    }
    // 发送数据
    func sendData(dataString:NSString)
    {
        let data:NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding)!
        self.outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
    }
    func readData()->NSString
    {

        var buffer = [UInt8](count: 1024, repeatedValue: 0)
        let len = self.inputStream?.read(&buffer, maxLength: buffer.count)
        var res:NSString = ""
        //
        if len > 0
        {
            res = NSString(bytes: buffer, length: buffer.count, encoding: NSUTF8StringEncoding)!
        }
        return res
    }
}