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:@"连接失败\n"];

        return;

    }

    else

    {

        NSLog(@"连接成功");

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

        // 读取接收的数据

        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:@"\n"];

    [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;

}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。