iOS CFsocket

来源:互联网 发布:4399创世兵魂刷枪软件 编辑:程序博客网 时间:2024/06/05 15:42

CF Socket简介

由于iPhoneSDK里面提供的接口是CF Socket。简单DEMO下。

Socket接口是TCP/IP网络的APISocket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket口。

Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的Socket数据传输是一种特殊的I/OSocket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式SocketSOCK_STREAM)和数据报式SocketSOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

//定义读写的 stream.

CFReadStreamRef myReadStream = NULL;

CFReadStreamRef myWriteStream = NULL;

//Socket的建立下面有参数的原始声明

///* This is a synonym for NULL, if you'd rather use a named constant. */

//CF_EXPORT

//const CFAllocatorRef kCFAllocatorDefault;

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,

                                   /*host*/ ,

                                   /*端口*/,

                                   &myReadStream,

                                   &myWriteStream);


//打开Stream.

if (myReadStream != NULL && CFReadStreamOpen(myReadStream))

{

    UInt8 readBuffer[10];

    while (CFReadStreamHasBytesAvailable(stream))

    {

        //进行读操作

        CFReadStreamRead(stream, buffer, 10);

    }

}


//写操作

if (myWriteStream != NULL && CFWriteStreamOpen(myWriteStream))

{

    //写一个byte.

    UInt8 writeBuffer[1];

    writeBuffer[0] = 42;

    CFWriteStreamWrite(stream, writeBuffer, 1);

}


//关闭Stream

CFReadStreamClose(myReadStream);

CFWriteStreamClose(myWriteStream);

// Release掉不需要的资源

CFRelease(myReadStream);

CFRelease(myWriteStream);


客户端:

导入头文件:

#import <sys/socket.h>

#import <netinet/in.h>

#import <arpa/inet.h>

#import <unistd.h>


1、创建连接

CFSocketContext sockContext =

{

    0, //结构体的版本,必须为0

   self// 一个任意指针的数据,可以用在创建时CFSocket对象相关联。这个指针被传递给所有的上下文中定义的回调。

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

    NULL, NULL

};


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

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

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

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

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

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

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

                       );


if (_socket != nil)

{

    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(courceRef);

}


2、设置回调函数

// socket回调函数的格式:

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

{

    if (data != NULL)

    {

        //socketkCFSocketConnectCallBack时,失败时回调失败会返回一个错误代码指针,其他情况返回NULL

        NSLog(@"连接失败");

        return;

    }

    TCPClient *client = (TCPClient *)info;

    //读取接收的数据

    [info performSlectorInBackground:@selector(readStream) withObject:nil];

}


3、接收发送数据

//读取接收的数据

- (void)readStream

{

    char buffer[1024];

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

    //与本机关联的Socket 如果已经失效返回-1:INVALID_SOCKET

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

    {

        NSLog(@"%@", [NSString stringWithUTF8String:buffer]);

    }

}


//发送数据

- (void)sendMessage

{

    NSString *stringTosend = @"你好";

    char *data = [stringTosend UTF8String];

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

}



服务器端:

CFSockteRef _socket;

CFWriteStreamRef outputStream = NULL;


int setupSocket()

{

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

    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(port);

    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;

}


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

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

        }

        NSLog(@"%@ connected.", inet_ntoa( ((struct sockaddr_in *)name)->sin_addr )):

        

        CFReadStreamRef iStream;

        CFWriteStreamRef oStream;

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

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

        if (iStream && oStream)

        {

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

            //回调函数,当有可读的数据时调用

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

            {

                exit(1);

            }

            

            if (!CFReadStreamSetClient(iStream, kCFStreamEventCanAcceptBytes, writeStream, &streamContext))

            {

                exit(1);

            }

            

            CFReadStreamScheduleWithRunLoop(iStream, CFRunLoopGetCurrent(), kCFRunLoopCommomModes);

            CFWriteStreamScheduleWithRunLoop(wStream, CFRunLoopGetCurrent(), kCFRunLoopCommomModes);

            CFReadStreamOpen(iStream);

            CFWriteStreamOpen(wStream);

        }

        else

        {

            close(nativeSocketHandle);

        }

    }

}


//读取数据

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

{

    UInt8 buff[255];

    CFReadStreamRead(stream, buff, 255);

    printf("received: %s", buff);

}


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

{

    outputStream = stream;

}


main

{

    char *str = "nihao";

    

    if (outputStream != NULL)

    {

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

    } 

    else

    {

        NSLog(@"Cannot send data!");

    }

}


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

void runLoopInThread()

{

    int res = setupSocket();

    if (!res)

    {

        exit(1);

    }

     //运行当前线程的CFRunLoop对象

    CFRunLoopRun();

}

0 0
原创粉丝点击