zoukankan      html  css  js  c++  java
  • ios Socket套接字编程(转)

    Server端:
        用CFSocketCreate()创建socket;
        再用CFSocketSetAddress()设置地址;
        再用CFSocketCreateRunLoopSource()把socket添加到runloop;
        在socket的回调方法中用CFStreamCreatePairWithSocket()创建绑定到socket的
    CFReadStreamReff流,再将CFReadStreamRef流转换成NSInputStream类型,设置好delegate,添加到runloop,最后open;
        在- (void)stream:(NSStream*)aStream handleEvent:(NSStreamEvent)eventCode方法中处理NSStreamEventHasBytesAvailable事件读取流中的数据。
    
    Client端:
    
        用CFSocketCreate()创建socket;
        再用CFSocketConnectToAddress()连接到指定地址;
        再用CFSocketCreateRunLoopSource()把socket添加到runloop;
        在socket的回调方法中用CFStreamCreatePairWithSocket()创建绑定到socket的
    CFWriteStreamRef流,再将CFReadStreamRef流转换成NSInputStream类型,设置好delegate,添加到runloop,最后open;
        在- (void)stream:(NSStream*)aStream handleEvent:(NSStreamEvent)eventCode方法中处理NSStreamEventHasSpaceAvailable事件向流中写数据。
    
        如果我跳过创建socket,直接使用CFStreamCreatePairWithSocketToHost创建CFWriteStreamRef流,就不会出问题,这是为什么?请高手指教。
    
    

    Client:

    -(void)CreateConnect:(NSString*)strAddress

    {

        CFSocketContext sockContext = {0, // 结构体的版本,必须为0

            self,

            NULL, // 一个定义在上面指针中的retain的回调, 可以为NULL

            NULL,

            NULL};

        _socket = CFSocketCreate(kCFAllocatorDefault, // 为新对象分配内存,可以为nil

                                 PF_INET, // 协议族,如果为0或者负数,则默认为PF_INET

                                 SOCK_STREAM, // 套接字类型,如果协议族为PF_INET,则它会默认为SOCK_STREAM

                                 IPPROTO_TCP, // 套接字协议,如果协议族是PF_INET且协议是0或者负数,它会默认为IPPROTO_TCP

                                 kCFSocketConnectCallBack, // 触发回调函数的socket消息类型,具体见Callback Types

                                 TCPClientConnectCallBack, // 上面情况下触发的回调函数

                                 &sockContext // 一个持有CFSocket结构信息的对象,可以为nil

                                 );

        if(_socket != NULL)

        {

            struct sockaddr_in addr4;   // IPV4

            memset(&addr4, 0, sizeof(addr4));

            addr4.sin_len = sizeof(addr4);

            addr4.sin_family = AF_INET;

            addr4.sin_port = htons(8888);

            addr4.sin_addr.s_addr = inet_addr([strAddress UTF8String]);  // 把字符串的地址转换为机器可识别的网络地址

            

            // 把sockaddr_in结构体中的地址转换为Data

            CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4));

            CFSocketConnectToAddress(_socket, // 连接的socket

                                     address, // CFDataRef类型的包含上面socket的远程地址的对象

                                     -1  // 连接超时时间,如果为负,则不尝试连接,而是把连接放在后台进行,如果_socket消息类型为kCFSocketConnectCallBack,将会在连接成功或失败的时候在后台触发回调函数

                                     );

            CFRunLoopRef cRunRef = CFRunLoopGetCurrent();    // 获取当前线程的循环

            // 创建一个循环,但并没有真正加如到循环中,需要调用CFRunLoopAddSource

            CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0);

            CFRunLoopAddSource(cRunRef, // 运行循环

                               sourceRef,  // 增加的运行循环源, 它会被retain一次

                               kCFRunLoopCommonModes  // 增加的运行循环源的模式

                               );

            CFRelease(sourceRef);

            NSLog(@"connect ok");

        }

    }

    // socket回调函数,同客户端

    static void TCPClientConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)

    {

         ViewController *client = (ViewController *)info;

        if (data != NULL)

        {

            NSLog(@"连接失败");

            [client.TextView insertText:@"连接失败 "];

            return;

        }

        else

        {

            NSLog(@"连接成功");

            [client.TextView insertText:@"连接成功 "];

            // 读取接收的数据

            g_viewPage = client;

            [client StartReadThread];

            

        }

    }

    -(void)StartReadThread

    {

            NSThread *InitThread = [[NSThread alloc]initWithTarget:self selector:@selector(InitThreadFunc:) object:self];

            [InitThread start];

    }

    -(void)InitThreadFunc:(id)sender

    {

        while (1) {

            [self readStream];

        }

    }

     // 读取接收的数据

    -(void)readStream

    {

        char buffer[1024];

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        NSString *str = @"服务器发来数据:";

        recv(CFSocketGetNative(_socket), buffer, sizeof(buffer), 0);

        {

            str = [str stringByAppendingString:[NSString stringWithUTF8String:buffer]];

        }

        NSLog(str);

        //回界面显示信息

        [self performSelectorOnMainThread:@selector(ShowMsg:) withObject:str waitUntilDone:NO];

        [pool release];

    }

    -(void)ShowMsg:(id)sender

    {

        NSString *str = sender;

        str = [str stringByAppendingString:@" "];

        [self.TextView insertText:str];

    }

     // 发送数据

    - (void)sendMessage {

        NSLog(@"hello Server");

        char *data = "hello Server";

        send(CFSocketGetNative(_socket), data, strlen(data) + 1, 0);

    }

    - (IBAction)SendMessageTouch:(id)sender {

        [self sendMessage];

    }

    - (IBAction)TouchConnectServer:(id)sender {

        NSString *serverIp = self.textField.text;

         [self CreateConnect:serverIp];

    }

    - (void)dealloc {

        [_TextView release];

        [_textField release];

        [super dealloc];

    }

    CFWriteStreamRef outputStream;

    Sever:

    @implementation SocketServer

    -(int)setupSocket

    {

        CFSocketContext sockContext = {0, // 结构体的版本,必须为0

            self,

            NULL, // 一个定义在上面指针中的retain的回调, 可以为NULL

            NULL,

            NULL};

        _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, TCPServerAcceptCallBack, &sockContext);

        if (NULL == _socket) {

            NSLog(@"Cannot create socket!");

            return 0;

        }

        

        int optval = 1;

        setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_REUSEADDR, // 允许重用本地地址和端口

                   (void *)&optval, sizeof(optval));

        

        struct sockaddr_in addr4;

        memset(&addr4, 0, sizeof(addr4));

        addr4.sin_len = sizeof(addr4);

        addr4.sin_family = AF_INET;

        addr4.sin_port = htons(8888);

        addr4.sin_addr.s_addr = htonl(INADDR_ANY);

        CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4));

        

        if (kCFSocketSuccess != CFSocketSetAddress(_socket, address))

        {

            NSLog(@"Bind to address failed!");

            if (_socket)

                CFRelease(_socket);

            _socket = NULL;

            return 0;

        }

        

        CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent();

        CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0);

        CFRunLoopAddSource(cfRunLoop, source, kCFRunLoopCommonModes);

        CFRelease(source);

        

        return 1;

    }

    -(void) SendMessage

    {

        char *str = "你好 Client";

        uint8_t * uin8b = (uint8_t *)str;

        if (outputStream != NULL)

        {

            CFWriteStreamWrite(outputStream, uin8b, strlen(str) + 1);

        }

        else {

            NSLog(@"Cannot send data!");

        }

        

    }

    // 开辟一个线程线程函数中

    -(void) StartServer

    {

        int res = [self  setupSocket];

        if (!res) {

            exit(1);

        }

        NSLog(@"运行当前线程的CFRunLoop对象");

        CFRunLoopRun();    // 运行当前线程的CFRunLoop对象

    }

    -(void)ShowMsgOnMainPage:(NSString*)strMsg

    {

        [self.delegate ShowMsg:strMsg];

    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    // socket回调函数

    static void TCPServerAcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)

    {

        if (kCFSocketAcceptCallBack == type)

        {

            // 本地套接字句柄

            CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;

            uint8_t name[SOCK_MAXADDRLEN];

            socklen_t nameLen = sizeof(name);

            if (0 != getpeername(nativeSocketHandle, (struct sockaddr *)name, &nameLen)) {

                NSLog(@"error");

                exit(1);

            }

            CFReadStreamRef iStream;

            CFWriteStreamRef oStream;

            // 创建一个可读写的socket连接

            CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &iStream, &oStream);

            if (iStream && oStream)

            {

                CFStreamClientContext streamContext = {0, info, NULL, NULL};

                if (!CFReadStreamSetClient(iStream, kCFStreamEventHasBytesAvailable,readStream, &streamContext))

                {

                    exit(1);

                }

                

                if (!CFWriteStreamSetClient(oStream, kCFStreamEventCanAcceptBytes, writeStream, &streamContext))

                {

                    exit(1);

                }

                CFReadStreamScheduleWithRunLoop(iStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

                CFWriteStreamScheduleWithRunLoop(oStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

                CFReadStreamOpen(iStream);

                CFWriteStreamOpen(oStream);

            } else

            {

                close(nativeSocketHandle);

            }

        }

    }

    // 读取数据

    void readStream(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)

    {

        UInt8 buff[255];

        CFReadStreamRead(stream, buff, 255);

        

        ///根据delegate显示到主界面去

        NSString *strMsg = [[NSString alloc]initWithFormat:@"客户端传来消息:%s",buff];

        SocketServer *info = (SocketServer*)clientCallBackInfo;

        [info ShowMsgOnMainPage:strMsg];

    }

    void writeStream (CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)

    {

        outputStream = stream;

    }

  • 相关阅读:
    听说你的MES系统又失败了?
    GROUP BY你都不会!ROLLUP,CUBE,GROUPPING详解
    对 MES 感兴趣?赶紧看过来!
    SQL 高级查询(层次化查询,递归)
    智能制造概念
    简单又实用的分享!SharePoint母版页引用(实战)
    原创分享!SharePoint母版页修改(实战)
    入门者必看!SharePoint之CAML总结(实战)
    新手必看!Office Web Apps 2013 安装与配置(实战)
    SharePoint布局页引用(实战)
  • 原文地址:https://www.cnblogs.com/fakemessi/p/4380154.html
Copyright © 2011-2022 走看看