ios socket长链接

服务端

需要SystemConfiguration.framework CFNetwork.framework

服务端

#import <Foundation/Foundation.h>

#import <sys/socket.h>

#import <netinet/in.h>

#import <arpa/inet.h>

#import <unistd.h>


@interface SocketServer : NSObject

{

    CFSocketRef _socket;

}

@property (retain, nonatomic) id delegate;

-(void) StartServer;

-(void) SendMessage;

@end

服务端 .m

#import "SocketServer.h"

CFWriteStreamRef outputStream;


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

}

@end

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

{

    server = [[SocketServer alloc]init];

    server.delegate = self;

    // Insert code here to initialize your application

   

}

- (IBAction)SendMessageToClient:(id)sender {

    [server SendMessage];

}


- (IBAction)touchStartServer:(id)sender {

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

    [InitThread start];

    self.textField.stringValue = @"服务启动成功";

}

-(void)InitThreadFunc:(id)sender

{

    [server StartServer];

}

-(void)ShowMsg:(NSString*)strMsg

{

    NSLog(strMsg);

    self.textField.stringValue = [NSString stringWithFormat:@"%@\n%@",self.textField.stringValue, strMsg];

}

@end



客户端

#import <UIKit/UIKit.h>


@interface ViewController : UIViewController

{

    CFSocketRef _socket;

}

- (IBAction)SendMessageTouch:(id)sender;

- (IBAction)TouchConnectServer:(id)sender;

@property (retain, nonatomic) IBOutlet UITextView *TextView;

@property (retain, nonatomic) IBOutlet UITextField *textField;


@end

-(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];

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值