MAC系统基于UNIX的核心系统增强了系统的稳定性、性能以及响应能力。由于unix需要付费,以及版本基本上不更新,很多采用unix系统的电脑转用linux,unix处于停滞不前状态,而linux由于是开源的,免费的,所以全球很多技术大牛在不断改进它,给它增加新技术,增加新理念,使它日新月异的发展。所以mac os后期主要借鉴linux的新技术,所以现在的mac os越来越像linux,linux也是来源于unix,他们师兄弟两个青出于蓝而胜于蓝。因此linux的socket的编程对苹果系统仍然有效。可以通过socket直接发送数据请求,可以通过fd创建多个连接,通过select对各个fd进行监控。要注意黏包的问题,可能网络不好或一段高频率的写数据不同的消息格式数据,开始可能没有立刻收到响应消息,有可能突然收到多个消息拼接在一起的字符串。有一种通而不达的情况,可能刚创建select后用select监听,服务器返回准备中,但是直到3.5分钟才能返回失败。
这个是我当时研究socket长连接的例子,由于非完整项目,没有解决粘包问题,由于只实现了部分功能,没有对消息格式进行严格定义和解析。只是实现了异步socket通信(收发消息)部分。不过我做的新项目这类的项目已经完美解决,由于公司信息案安全原因,不能泄露具体项目内容,但是它的原理是一样的,而且篇文章基本上没有加业务逻辑,所以更简单更容易看懂。
运行在mac的socket服务器demo下载地址:
http://download.csdn.net/download/jia12216/8929167
socket客户端app下载地址:http://download.csdn.net/download/jia12216/8929153
用java写的socket服务器测试桩下载地址:http://download.csdn.net/download/jia12216/8929101
运行在window电脑上socket服务器demo下载地址:http://download.csdn.net/download/jia12216/8929085
第三方库socket异步通信(robbiehanson/CocoaAsyncSocket)下载地址:https://github.com/robbiehanson/CocoaAsyncSocket/
注意:
inet_addr(“172.16.28.153”);这个要填你服务运行的电脑的ip,若有域名最好填域名(如:www.baidu.com).
.sin_port = htons(9123);这个你要连接的端口号,服务器和客户端的域名和端口好要一致。
客户端代码:
-(void)creatPushConnection { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ unsigned char recv_msg[BUFFER_SIZE+3]; NSString *dec = nil; NSInteger iStart = 0; unsigned char input_msg[4096]; int server_sock_fd; int sd; BOOL handleFlag = NO; NSDate *curDate = nil; unsigned char msg[4096+1]; NSUInteger len = 0; //unsigned int m = 0; long n = 0; unsigned char c; long byte_num = 0; unsigned char *p = recv_msg; char arr[BUFFER_SIZE+1]; long m = 0, m1 = 0; NSString *message = nil; NSString *str1=nil; NSString *str2=nil; unsigned int k = 0; NSError *error = nil; Boolean bFlag = YES; Boolean bstrEndFlag = NO; NSData *da = nil; g_LoginShiftState = SHIFT_STATE_INIT; g_fd = -1; server_sock_fd = -1; SKIP: //注意这段绑定ip和端口号的代码要放在这里防止出现网络类型变更,如:从wifi切换到4G,或4G切换到3G struct sockaddr_in server_addr; server_addr.sin_len = sizeof(struct sockaddr_in); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(9123); //server_addr.sin_addr.s_addr = inet_addr("172.16.28.106"); //server_addr.sin_addr.s_addr = inet_addr("172.16.28.25"); //server_addr.sin_addr.s_addr = inet_addr("172.16.28.157"); //server_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); server_addr.sin_addr.s_addr = inet_addr("172.16.28.153"); bzero(&(server_addr.sin_zero),8); if(g_fd != -1) { close(g_fd); } g_pushTime = 0; g_LoginShiftState = SHIFT_STATE_INIT; g_fd = -1; server_sock_fd = -1; server_sock_fd = socket(AF_INET, SOCK_STREAM, 0); sd = server_sock_fd; if (server_sock_fd == -1) { NSLog(@"socket error"); return; } while(1) { g_fdWriteFlag = YES; //将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完成,网络不通75秒才返回结果 fcntl(socket, F_SETFL, O_NDELAY); int i = connect(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)); NSLog(@"i= %d\n", i); //发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧在进行还没有完成. //getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int)); 来得到error的值,如果为零,则connect成功. if ( i ==0) { g_fd = server_sock_fd;; fd_set client_fd_set; fd_set read_fd_set; struct timeval tv; tv.tv_sec = 10; tv.tv_usec = 0; //int max_fd = pipeFd; int max_fd = server_sock_fd; i = 0; while (1) { g_fdWriteFlag = YES; bzero(input_msg, 1024); FD_ZERO(&read_fd_set); FD_SET(server_sock_fd, &read_fd_set); struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; i = 0; if(max_fd < server_sock_fd) { max_fd = server_sock_fd; } int ret = select(max_fd + 1, &read_fd_set, NULL, NULL, &tv); if (ret < 0 ) { NSLog(@"select 出错!\n"); goto SKIP; } else if(ret ==0){ NSLog(@"select 超时!\n"); FD_ZERO(&client_fd_set); FD_ZERO(&read_fd_set); FD_SET(server_sock_fd, &client_fd_set); FD_SET(server_sock_fd, &read_fd_set); tv.tv_sec = 1; tv.tv_usec = 0; //socket一般都处于可写状态,除了网卡满了写不进去的罕见情况,所以该处侦听一般都是立刻响应 ret = select(max_fd + 1, &read_fd_set, &client_fd_set, NULL, &tv); //[g_puTc lock]; if (ret < 0 ) { NSLog(@"select 出错!\n"); //[g_puTc unlock]; goto SKIP; } else if(ret ==0){ NSLog(@"select 超时!\n"); //[g_puTc unlock]; continue; } else { //先把消息接收过来,后面再处理,防止再处理消息时,连接异常。 if (FD_ISSET(server_sock_fd, &read_fd_set)) { NSLog(@"ret2= %d\n", ret); bzero(recv_msg, BUFFER_SIZE); long byte_num = recv(server_sock_fd,recv_msg,BUFFER_SIZE,0); if (byte_num > 0) { if (byte_num > BUFFER_SIZE) { byte_num = BUFFER_SIZE; } recv_msg[byte_num] = '\0'; NSLog(@"服务器:%s\n",recv_msg); handleFlag = YES; }else if(byte_num < 0){ NSLog(@"接收消息出错!\n"); //从实际运行上发现,若出现接收消息错误,后面无论如何接收消息都报同样的错误,所以还是关闭SOCKET,重新建立连接吧! close(server_sock_fd); goto SKIP; }else{ //当socket可读,但是读到的字节数为0,说明是服务端退出 close(server_sock_fd); NSLog(@"服务器端退出!\n"); goto SKIP; } } //判断是否可写,若可写,并且有消息可以发送就像服务器推送消息。 if (FD_ISSET(server_sock_fd, &client_fd_set)) { bzero(input_msg, BUFFER_SIZE); if((g_LoginShiftState == SHIFT_STATE_INIT) || (g_LoginShiftState == SHIFT_STATE_UNLOGIN)) { bzero(msg, 4096); snprintf(msg, sizeof(msg), "#################################################################POSITON latitude = %f, longitude = %f", g_latitude, g_longitude); bzero(input_msg, 4096); snprintf(msg, sizeof(msg), "{\"head\":{\"token\":\"%s\",\"cmd\":\"0002\",\"result\":\"0\",\"ecode\":\"\",\"msg\":\"中国01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789e\"},\"body\":{}}", [g_token UTF8String]); NSLog(@"msg= %s\n", msg); len = strlen(msg); snprintf(input_msg+2, len+1, "%s", msg); NSUInteger m = 0; NSUInteger j = 1; m = len; if(m/256 == 0) { input_msg[j--] = m % 256; input_msg[j] = 0; } else if(m/65536 == 0) { input_msg[j--] = m % 256; input_msg[j] = m/256; } NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@input_msg1=%s\n", input_msg+2); ret = send(server_sock_fd, input_msg, len + 2, 0); if (ret == -1) { NSLog(@"发送消息出错!\n"); NSLog(@"ret7= %d\n", ret); } else { if((g_LoginShiftState == SHIFT_STATE_INIT) || (g_LoginShiftState == SHIFT_STATE_UNLOGIN)) { g_LoginShiftState = SHIFT_STATE_LOGINING; } NSLog(@"ret8= %d\n", ret); } } else if(g_LoginShiftState == SHIFT_STATE_LOGINING) { curDate = [NSDate date]; NSTimeInterval nowTime = [curDate timeIntervalSince1970]*1; if(nowTime - g_pushTime >= 15*2) { bzero(msg, 300); snprintf(msg, sizeof(msg), "#################################################################POSITON latitude = %f, longitude = %f", g_latitude, g_longitude); bzero(input_msg, BUFFER_SIZE); snprintf(msg, sizeof(msg), "[{\"head\":{\"token\":\"%s\",\"cmd\":\"0001\",\"result\":\"0\",\"ecode\":\"\",\"msg\":\"中国\"},\"body\":{\"latitude\":%f,\"longitude\":%f}}]", [g_token UTF8String], g_latitude, g_longitude); NSLog(@"msg= %s\n", msg); len = strlen(msg); snprintf(input_msg+2, len+1, "%s", msg); NSUInteger m = 0; NSUInteger j = 1; m = len; if(m/256 == 0) { input_msg[j--] = m % 256; input_msg[j] = 0; } else if(m/65536 == 0) { input_msg[j--] = m % 256; input_msg[j] = m/256; } NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@input_msg2=%s\n", input_msg+2); while (!g_fdWriteFlag) { sleep(3); } g_fdWriteFlag = NO; ret = send(server_sock_fd, input_msg, len + 2, 0); if (ret == -1) { NSLog(@"发送消息出错!\n"); NSLog(@"ret7= %d\n", ret); g_fdWriteFlag = YES; //[g_puTc unlock]; goto SKIP; } else { NSLog(@"ret8= %d\n", ret); g_pushTime = nowTime; } ret = send(server_sock_fd, input_msg, len + 2, 0); if (ret == -1) { NSLog(@"发送消息出错!\n"); NSLog(@"ret7= %d\n", ret); g_fdWriteFlag = YES; //[g_puTc unlock]; goto SKIP; } else { NSLog(@"ret8= %d\n", ret); g_pushTime = nowTime; } ret = send(server_sock_fd, input_msg, len + 2, 0); if (ret == -1) { NSLog(@"发送消息出错!\n"); NSLog(@"ret7= %d\n", ret); g_fdWriteFlag = YES; //[g_puTc unlock]; goto SKIP; } else { NSLog(@"ret8= %d\n", ret); g_pushTime = nowTime; } g_fdWriteFlag = YES; } } } //在此处处理服务器发过来的消息 //handleMessage } //[g_puTc unlock]; continue; } else { i = 10 - tv.tv_sec; NSLog(@"i= %d\n", i); NSLog(@"&client_fd_set= %d\n", &client_fd_set); if (FD_ISSET(server_sock_fd, &read_fd_set)) { NSLog(@"ret2= %d\n", ret); str1 = nil; str2 = nil; bFlag = YES; bzero(recv_msg, BUFFER_SIZE+3); byte_num = recv(server_sock_fd,recv_msg,MESSAGE_HEADER_SIZE,0); if (byte_num == 2) { // if (byte_num > BUFFER_SIZE) { // byte_num = BUFFER_SIZE; // } //recv_msg[byte_num] = '\0'; //NSLog(@"服务器:%s\n",recv_msg+2); //dec = nil; //iStart =h 0; //bzero(arr, BUFFER_SIZE+1); //memcpy(arr, recv_msg, BUFFER_SIZE); c = recv_msg[0]; //NSLog(@"服务器:%d\n",c); n = c*256; //NSLog(@"服务器:%d\n",n); c = recv_msg[1]; //NSLog(@"服务器:%d\n",c); n = n + c; while (1) { NSLog(@"服务器:消息队列解析。\n"); NSLog(@"服务器:%ld\n",n); m1 = BUFFER_SIZE; bstrEndFlag = NO; if(n == 0) { NSLog(@"服务器:消息错误\n"); break; } else { bzero(recv_msg, BUFFER_SIZE+3); if(n <= BUFFER_SIZE) { //n = n; byte_num = recv(server_sock_fd,recv_msg,n + 2,0); NSLog(@"服务器:n = %d, byte_num = %d\n",n, byte_num); if(byte_num == n) { str1 = [NSString stringWithCString:recv_msg encoding:NSUTF8StringEncoding]; NSLog(@"服务器:%@\n",str1); break; } else if(byte_num == n + 2) { str1 = [NSString stringWithCString:recv_msg encoding:NSUTF8StringEncoding]; NSLog(@"服务器:%@\n",str1); c = recv_msg[byte_num-2]; //NSLog(@"服务器:%d\n",c); n = c*256; //NSLog(@"服务器:%d\n",n); c = recv_msg[byte_num-1]; //NSLog(@"服务器:%d\n",c); n = n + c; break; } else { NSLog(@"服务器:消息格式错误\n"); break; } // str1 = nil; // str2 = nil; // // bzero(recv_msg, BUFFER_SIZE+1); // byte_num = recv(server_sock_fd,recv_msg,MESSAGE_HEADER_SIZE,0); // if (byte_num != 2) // { // break; // } } else { while (m1 > 0) { NSLog(@"服务器:消息字符串解析。\n"); bzero(recv_msg, BUFFER_SIZE+3); byte_num = recv(server_sock_fd,recv_msg,m1,0); if((byte_num != BUFFER_SIZE) && (!bstrEndFlag)) { NSLog(@"服务器:消息格式错误\n"); bFlag = NO; break; } else if((byte_num == m1) && (m1 == n + 2) && (bstrEndFlag)) { bFlag = YES; c = recv_msg[m1-2]; NSLog(@"服务器:c = %d\n",c); n = c*256; c = recv_msg[m1-1]; NSLog(@"服务器:c = %d\n",c); n = n + c; NSLog(@"服务器:n = %d\n",n); recv_msg[m1-2] ='\0'; recv_msg[m1-1] = '\0'; } else if((byte_num < n) && (bstrEndFlag)) { NSLog(@"服务器:消息格式错误\n"); bFlag = NO; break; } else if((byte_num == n) && (m1 == n + 2) && (bstrEndFlag)) { bFlag = NO; } NSLog(@"服务器:((byte_num == n) && (m1 == n + 2) && (bstrEndFlag)) = %d\n",((byte_num == n) && (m1 == n + 2) && (bstrEndFlag))); NSLog(@"服务器:byte_num = %d, n = %d, bFlag = %d, m1 = %d\n",byte_num, n, bFlag, m1); if(str1 == nil) { str1 = [NSString stringWithCString:recv_msg encoding:NSUTF8StringEncoding]; } else { str2 = [NSString stringWithCString:recv_msg encoding:NSUTF8StringEncoding]; str1 = [str1 stringByAppendingString:str2]; } if(bstrEndFlag) { NSLog(@"服务器:%@\n",str1); break; } //NSLog(@"服务器:m1 == BUFFER_SIZE = %d\n",m1 == BUFFER_SIZE); n = n - BUFFER_SIZE; if(n > BUFFER_SIZE) { m1 = BUFFER_SIZE; } else if((m1 == BUFFER_SIZE) && (n > 0)) { m1 = n + 2; bstrEndFlag = YES; NSLog(@"服务器:m1 = %ld\n",m1); } else { break; } } if(bFlag) { NSLog(@"服务器:%@\n",str1); //在此处处理服务器发过来的消息 //handleMessage str1 = nil; str2 = nil; } else { break; } } } //while(1) // { // bzero(msg, BUFFER_SIZE); // memcpy(msg, p+2, BUFFER_SIZE); // //NSLog(@"服务器:%s\n",msg); // bzero(arr, BUFFER_SIZE); // //memcpy(arr, p+2, strlen(recv_msg+2)); // if(n < BUFFER_SIZE) // { // memcpy(arr, p+2, n); // arr[BUFFER_SIZE] = '\0'; // NSLog(@"服务器:%s\n",arr) // NSString *str=[NSString stringWithCString:arr encoding:NSUTF8StringEncoding]; // //NSLog(@"服务器:%d\n",[str length]); // //NSLog(@"服务器:%@\n",str); // NSError *error = nil; // // NSData *da= [str dataUsingEncoding:NSUTF8StringEncoding]; // NSLog(@"服务器:%d\n",[da length]); // // // NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:da options:NSJSONReadingMutableLeaves error:&error]; // if(dic != nil) // { // NSLog(@"服务器:%@\n",dic); // NSLog(@"服务器:%d\n",[error code]); // // @try // { // NSDictionary * dicinfo = [dic objectForKey:@"head"]; // NSString * s1 = [dic objectForKey:@"body"]; // NSLog(@"服务器:%@\n",s1); // NSLog(@"服务器:%@\n",dicinfo); // //NSDictionary * dicinfo2 = [dic objectForKey:@"head1"]; // NSString * s2 = [dic objectForKey:@"bo1"]; // NSLog(@"服务器:%@\n",s2); // // }@catch (NSException * e) { // NSLog(@@"Exception: %@", e); // // } // } // else // { // NSLog(@"服务器:消息格式错误"); // } // // } // else // { // // m = n; // memcpy(arr, p+2, n); // arr[BUFFER_SIZE] = '\0'; // NSLog(@"服务器:%s\n",arr) // str1 = [NSString stringWithCString:arr encoding:NSUTF8StringEncoding]; // bzero(recv_msg, BUFFER_SIZE); // byte_num = recv(server_sock_fd,recv_msg,BUFFER_SIZE,0); // while (1) // { // p = recv_msg; // memcpy(arr, p+2, n); // arr[BUFFER_SIZE] = '\0'; // NSLog(@"服务器:%s\n",arr) // str2 = [NSString stringWithCString:arr encoding:NSUTF8StringEncoding]; // message = [str1 stringByAppendingString:str2]; // str1 = message; // if(n == [str1 length]) // { // // } // } // // } // // // // break; // // // // // } } //[self decodePushMessage:recv_msg:dec:&iStart]; } else if(byte_num == 1) { NSLog(@"无法识别的消息!\n"); } else if(byte_num < 0) { NSLog(@"接收消息出错!\n"); //从实际运行上发现,若出现接收消息错误,后面无论如何接收消息都报同样的错误,所以还是关闭SOCKET,重新建立连接吧! close(server_sock_fd); goto SKIP; } else{ close(server_sock_fd); NSLog(@"服务器端退出!\n"); goto SKIP; //exit(0); } } FD_ZERO(&client_fd_set); FD_ZERO(&read_fd_set); FD_SET(server_sock_fd, &client_fd_set); FD_SET(server_sock_fd, &read_fd_set); tv.tv_sec = 1; tv.tv_usec = 0; //socket一般都处于可写状态,除了网卡满了写不进去的罕见情况,所以该处侦听一般都是立刻响应 ret = select(server_sock_fd + 1, &read_fd_set, &client_fd_set, NULL, &tv); //[g_puTc lock]; if (ret < 0 ) { NSLog(@"select 出错!\n"); //[g_puTc unlock]; goto SKIP; } else if(ret ==0){ NSLog(@"select 超时!\n"); //[g_puTc unlock]; continue; } else{ NSLog(@"ret4= %d\n", ((FD_ISSET(server_sock_fd, &client_fd_set)) && (FD_ISSET(server_sock_fd, &read_fd_set)))); i = 10 - tv.tv_sec; NSLog(@"i= %d\n", i); //先把消息接收过来,后面再处理,防止在处理消息时,连接异常。 if (FD_ISSET(server_sock_fd, &read_fd_set)) { NSLog(@"ret2= %d\n", ret); bzero(recv_msg, BUFFER_SIZE); long byte_num = recv(server_sock_fd,recv_msg,BUFFER_SIZE,0); if (byte_num > 0) { if (byte_num > BUFFER_SIZE) { byte_num = BUFFER_SIZE; } recv_msg[byte_num] = '\0'; NSLog(@"服务器:%s\n",recv_msg); handleFlag = YES; }else if(byte_num < 0){ NSLog(@"接受消息出错!\n"); }else{ close(server_sock_fd); NSLog(@"服务器端退出!\n"); goto SKIP; //exit(0); } } //判断是否可写,若可写,并且有消息可以发送就像服务器推送消息。 if (FD_ISSET(server_sock_fd, &client_fd_set)) { bzero(input_msg, BUFFER_SIZE); if((g_LoginShiftState == SHIFT_STATE_INIT) || (g_LoginShiftState == SHIFT_STATE_UNLOGIN)) { bzero(msg, BUFFER_SIZE); snprintf(msg, sizeof(msg), "#################################################################POSITON latitude = %f, longitude = %f", g_latitude, g_longitude); bzero(input_msg, BUFFER_SIZE); snprintf(msg, sizeof(msg), "{\"head\":{\"token\":\"%s\",\"cmd\":\"0002\",\"result\":\"0\",\"ecode\":\"\",\"msg\":\"\"},\"body\":{}}", [g_token UTF8String]); NSLog(@"msg= %s\n", msg); len = strlen(msg); snprintf(input_msg+2, len+1, "%s", msg); NSUInteger m = 0; NSUInteger j = 1; m = len; if(m/256 == 0) { input_msg[j--] = m % 256; input_msg[j] = 0; } else if(m/65536 == 0) { input_msg[j--] = m % 256; input_msg[j] = m/256; } NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@input_msg3=%s\n", input_msg+2); while (!g_fdWriteFlag) { sleep(3); } g_fdWriteFlag = NO; ret = send(server_sock_fd, input_msg, len + 2, 0); if (ret == -1) { NSLog(@"发送消息出错!\n"); NSLog(@"ret7= %d\n", ret); g_fdWriteFlag = YES; //[g_puTc unlock]; goto SKIP; } else { if((g_LoginShiftState == SHIFT_STATE_INIT) || (g_LoginShiftState == SHIFT_STATE_UNLOGIN)) { g_LoginShiftState = SHIFT_STATE_LOGINING; } NSLog(@"ret8= %d\n", ret); } g_fdWriteFlag = YES; } else if(g_LoginShiftState == SHIFT_STATE_LOGINING) { curDate = [NSDate date]; NSTimeInterval nowTime = [curDate timeIntervalSince1970]*1; if(nowTime - g_pushTime >= 15*2) { bzero(msg, 300); snprintf(msg, sizeof(msg), "#################################################################POSITON latitude = %f, longitude = %f", g_latitude, g_longitude); bzero(input_msg, BUFFER_SIZE); snprintf(msg, sizeof(msg), "{\"head\":{\"token\":\"%s\",\"cmd\":\"0001\",\"result\":\"0\",\"ecode\":\"\",\"msg\":\"\"},\"body\":{\"latitude\":%f,\"longitude\":%f}}", [g_token UTF8String], g_latitude, g_longitude); NSLog(@"msg= %s\n", msg); len = strlen(msg); snprintf(input_msg+2, len+1, "%s", msg); NSUInteger m = 0; NSUInteger j = 1; m = len; if(m/256 == 0) { input_msg[j--] = m % 256; input_msg[j] = 0; } else if(m/65536 == 0) { input_msg[j--] = m % 256; input_msg[j] = m/256; } NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@input_msg4=%s\n", input_msg+2); while (!g_fdWriteFlag) { sleep(3); } g_fdWriteFlag = NO; ret = send(server_sock_fd, input_msg, len + 2, 0); if (ret == -1) { NSLog(@"发送消息出错!\n"); NSLog(@"ret7= %d\n", ret); g_fdWriteFlag = YES; //[g_puTc unlock]; goto SKIP; } else { NSLog(@"ret8= %d\n", ret); g_pushTime = nowTime; } g_fdWriteFlag = YES; } } } //在此处处理服务器发过来的消息 //handleMessage //[g_puTc unlock]; } } } } else { close(server_sock_fd); //flag = 1; sleep(5); goto SKIP; } } }); }
服务端代码:
- (void)windowControllerDidLoadNib:(NSWindowController *)aController { [super windowControllerDidLoadNib:aController]; [_nsT setStringValue:@"set sth."]; struct sockaddr_in server_addr; server_addr.sin_len = sizeof(struct sockaddr_in); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(9123); //server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); server_addr.sin_addr.s_addr = inet_addr("172.16.28.123"); bzero(&(server_addr.sin_zero),8); char recv_msg[1024]; char input_msg[BUFFER_SIZE]; //创建socket int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_sock_fd == -1) { perror("socket error"); return; } //绑定socket int bind_result = bind(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (bind_result == -1) { perror("bind error"); return; } //listen if (listen(server_sock_fd, BACKLOG) == -1) { perror("listen error"); return; } int kq = kqueue(); if (kq == -1) { perror("创建kqueue出错!\n"); exit(1); } struct kevent event_change; EV_SET(&event_change, STDIN_FILENO, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); EV_SET(&event_change, server_sock_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); while (1) { struct timespec timeout = {10,0}; int ret = kevent(kq, NULL, 0, events, 10, &timeout); if (ret < 0) { printf("kevent 出错!\n"); continue; }else if(ret == 0){ printf("kenvent 超时!\n"); continue; }else{ //ret > 0 返回事件放在events中 for (int i = 0; i < ret; i++) { struct kevent current_event = events[i]; //kevent中的ident就是文件描述符 if (current_event.ident == STDIN_FILENO) { //标准输入 bzero(input_msg, BUFFER_SIZE); fgets(input_msg, BUFFER_SIZE, stdin); //输入 ".quit" 则退出服务器 if (strcmp(input_msg, QUIT_CMD) == 0) { exit(0); } for (int i=0; i<CONCURRENT_MAX; i++) { if (client_fds[i]!=0) { send(client_fds[i], input_msg, BUFFER_SIZE, 0); } } }else if(current_event.ident == server_sock_fd){ //有新的连接请求 struct sockaddr_in client_address; socklen_t address_len; int client_socket_fd = accept(server_sock_fd, (struct sockaddr *)&client_address, &address_len); if (client_socket_fd > 0) { int index = -1; for (int i = 0; i < CONCURRENT_MAX; i++) { if (client_fds[i] == 0) { index = i; client_fds[i] = client_socket_fd; break; } } if (index >= 0) { EV_SET(&event_change, client_socket_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); printf("新客户端(fd = %d)加入成功 %s:%d \n",client_socket_fd,inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); }else{ bzero(input_msg, BUFFER_SIZE); strcpy(input_msg, "服务器加入的客户端数达到最大值,无法加入!\n"); send(client_socket_fd, input_msg, BUFFER_SIZE, 0); printf("客户端连接数达到最大值,新客户端加入失败 %s:%d \n",inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); } } }else{ //处理某个客户端过来的消息 bzero(recv_msg, BUFFER_SIZE); long byte_num = recv((int)current_event.ident,recv_msg,BUFFER_SIZE,0); if (byte_num > 0) { if (byte_num > BUFFER_SIZE) { byte_num = BUFFER_SIZE; } recv_msg[byte_num] = '\0'; printf("客户端(fd = %d):%s\n",(int)current_event.ident,recv_msg); //sleep(3); bzero(input_msg, BUFFER_SIZE); strcpy(input_msg, "123454678!\n"); if(send((int)current_event.ident, input_msg, BUFFER_SIZE, 0) == -1) { perror("send error"); } else { printf("input_msg%s\n", input_msg); } //printf("input_msg %s:%d \n",inet_ntoa(((int)current_event.ident).sin_addr),ntohs(((int)current_event.ident).sin_port)); }else if(byte_num < 0){ printf("从客户端(fd = %d)接受消息出错.\n",(int)current_event.ident); }else{ EV_SET(&event_change, current_event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); close((int)current_event.ident); for (int i = 0; i < CONCURRENT_MAX; i++) { if (client_fds[i] == (int)current_event.ident) { client_fds[i] = 0; break; } } printf("客户端(fd = %d)退出了\n",(int)current_event.ident); } } } } } // Add any code here that needs to be executed once the windowController has loaded the document's window. }