使用select侦查客户端的连接以及接收客户端的数据
2013-11-05 17:07
691 查看
主要测试select的用法,同时包含socket/bind/listen/accept/connect/send/recv/close/closesocket等的使用
开始打开一个服务器socket。通过select侦查 1 键盘输入 2 客户的连接请求 3 客户连接之后的数据传送请求。
1 侦查键盘的输入,有的话就输入到bre变量中,测试其值,是-1的话退出循环进而退出程序。
2 serverSocket1 收到客户的连接请求后,accept出一个新的socket,放入subSockets[MAX_CLIENTS]中。
3 每一个有效的subSockets[] 都在select里侦查,有数据需要收的时候就读进来,printf出去
selectaccept.c:
selectclient.c:
开始打开一个服务器socket。通过select侦查 1 键盘输入 2 客户的连接请求 3 客户连接之后的数据传送请求。
1 侦查键盘的输入,有的话就输入到bre变量中,测试其值,是-1的话退出循环进而退出程序。
2 serverSocket1 收到客户的连接请求后,accept出一个新的socket,放入subSockets[MAX_CLIENTS]中。
3 每一个有效的subSockets[] 都在select里侦查,有数据需要收的时候就读进来,printf出去
selectaccept.c:
/* 主要测试select的用法,同时包含socket/bind/listen/accept/connect/send/recv/close/closesocket等的使用 开始打开一个服务器socket。通过select侦查 1 键盘输入 2 客户的连接请求 3 客户连接之后的数据传送请求。 1 侦查键盘的输入,有的话就输入到bre变量中,测试其值,是-1的话退出循环进而退出程序。 2 serverSocket1 收到客户的连接请求后,accept出一个新的socket,放入subSockets[MAX_CLIENTS]中。 3 每一个有效的subSockets[] 都在select里侦查,有数据需要收的时候就读进来,printf出去 对应的client 在selectclient.c里 */ #include <stdio.h> #ifdef WIN32 #include <winsock2.h> #include <ws2tcpip.h> #else #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/errno.h> #define closesocket close #endif #define LEN 1024 #define MAX_CLIENTS 32 int main() { char buf[LEN] ; int serverSocket1 ; int subSockets[MAX_CLIENTS] = {-1} ; int sockets = 0 , is; int selected ; int readed; struct sockaddr remoteAddr ; int size_remoteAddr = sizeof( remoteAddr ) ; struct sockaddr_in sockAddr_in = {0}; int nfds = 0 ; fd_set readfds ; int re ; int bre; struct timeval ttv= {0, 10000}; #ifdef WIN32 WSADATA wsd ; serverSocket1 = WSAStartup( WINSOCK_VERSION , &wsd ) ; #endif printf("start\n" ) ; serverSocket1 = socket( PF_INET , SOCK_STREAM , 0 ) ; if( serverSocket1 < 0 ) printf("open server socket 1 error\n" ) ; printf("open server socket %d \n" , serverSocket1 ) ; sockAddr_in.sin_family = AF_INET ; sockAddr_in.sin_addr.s_addr = 127+(1<<24) ;//127.0.0.1 // INADDR_ANY ; sockAddr_in.sin_port = 1800 ; re = bind( serverSocket1 , (struct sockaddr* )&sockAddr_in , sizeof( sockAddr_in ) ) ; printf(" bind ok %d\n" , re ) ; re = listen( serverSocket1 , 4 ) ; printf("listen ok %d\n" , re ) ; while ( 1 ) { // printf("1 time:%d\n" , GetTickCount() ) ; FD_ZERO( & readfds ) ; nfds = serverSocket1; FD_SET( serverSocket1 , & readfds ) ; #ifndef WIN32 FD_SET( 0 , & readfds ) ; //stdin,linux ; 只在uinx/linux下起作用,windows下会造成select错误WSAENOTSOCK #endif for( is = 0 ; is < sockets ; is ++ ) { FD_SET( subSockets[is] , &readfds ) ; if( nfds < subSockets[is] ) nfds = subSockets[is] ; } nfds ++ ; selected = select ( nfds , &readfds , 0 ,0 ,&ttv ) ; #ifdef WIN32 if( selected < 0 ) re = WSAGetLastError() ; //WSAENOTSOCK #endif if( selected <= 0 ) continue ; if( FD_ISSET( 0 , &readfds )) { /* 从stdin 标准输入-1的话整个程序退出 , 只在uinx/linux下起作用*/ scanf("%d", &bre) ; if( bre == -1 ) { printf("you enter -1 is to exit\n" ) ; break ; } } for( is = 0 ; is < sockets ; is ++ ) { if( FD_ISSET( subSockets[is] , &readfds ) ) { readed = recv( subSockets[is] , buf , LEN ,0 ) ; printf("readed=%d\n" , readed ) ; if( readed <= 0 ) { //对方已经关闭该socket,见注释1 ,在linux ,windows和cygwin下返回值一直是0 , errno 也是0 printf("error no : %d %s\n" , errno , sys_errlist[errno] ) ; closesocket( subSockets[is] ) ; subSockets[is] = subSockets[sockets-1] ; sockets -- ; } else printf("read from subSockets[%d] : %s\n" , is , buf ) ; } } if( FD_ISSET( serverSocket1 , &readfds ) && ( sockets < MAX_CLIENTS) ) {/*可以在readfds查到accept信号 因为客户方有连接需求时,会发送报文,所以它就变成可读状态 */ subSockets[sockets] = accept( serverSocket1 , &remoteAddr , &size_remoteAddr ) ; sockets ++ ; printf("connected romote address : %d\n" , ((struct sockaddr_in*)&remoteAddr)->sin_port ) ; } } if( serverSocket1 >= 0 ) closesocket( serverSocket1 ) ; for( is = 0 ; is < sockets ; is ++ ) { if( subSockets[is] >= 0 ) { closesocket( subSockets[is] ); } } return 0 ; } /* 注1:来自网上,但测试结果和他描述不一样 利用select()检测对方Socket关闭的问题: 仍然是本地Socket有东东可读,因为对方Socket关闭时,会发一个关闭连接 通知报文,会马上被select()检测到的。关于TCP的连接(三次握手)和关 闭(二次握手)机制,敬请参考有关TCP/IP的书籍。 不知是什么原因,UNIX好象没有提供通知进程关于Socket或Pipe对方关闭的 信号,也可能是cpu所知有限。总之,当对方关闭,一执行recv()或read(), 马上回返回-1,此时全局变量errno的值是115,相应的sys_errlist[errno] 为"Connect refused"(请参考/usr/include/sys/errno.h)。所以,在上 篇的for(;;)...select()程序块中,当有东西可读时,一定要检查recv()或 read()的返回值,返回-1时要作出关断本地Socket的处理,否则select()会 一直认为有东西读,其结果曾几令cpu伤心欲断针脚。 */
selectclient.c:
/* selectaccept.c 对应的 client */ #include <stdio.h> #include <string.h> #ifdef WIN32 #include <winsock2.h> #include <ws2tcpip.h> #else #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/errno.h> void Sleep ( int ms ) { struct timespec ts ; ts.tv_sec = ms/1000 ; ts.tv_nsec = (ms%1000)*1000000 ; nanosleep( &ts , 0 ) ; } #define closesocket close #endif #define LEN 1024 int main(int argc , char* argv[]) { char buf[LEN] = "client" ; int socket1 ; struct sockaddr_in remoteAddr ; int size_remoteAddr = sizeof( remoteAddr ) ; struct sockaddr_in sockAddr_in = {0 }; int re ; int ii = 0 ; int cancel ; #ifdef WIN32 WSADATA wsd ; re = WSAStartup( WINSOCK_VERSION , &wsd ) ; #endif if( argc < 2 ) return 1 ; socket1 = socket( PF_INET , SOCK_STREAM , 0 ) ; if( socket1 < 0 ) printf("open socket error\n" ) ; printf("open socket %d\n" , socket1 ) ; sockAddr_in.sin_family = AF_INET ; sockAddr_in.sin_addr.s_addr = INADDR_ANY ; sockAddr_in.sin_port = 2800 ; re = bind( socket1 , (struct sockaddr* )&sockAddr_in , sizeof( sockAddr_in ) ) ; // can ignore this line printf("bind :%d\n" , re ) ; // re may < 0 bind other port if 2800 is used remoteAddr.sin_family = AF_INET ; remoteAddr.sin_port = 1800 ; remoteAddr.sin_addr.s_addr = 127+(1<<24) ;// 127.0.0.1 re = connect( socket1 , (struct sockaddr* )&remoteAddr , size_remoteAddr ) ; printf(" connect : %d\n" , re ) ; if( re < 0 ) { printf("error no : %d %s\n" , errno , sys_errlist[errno] ) ; return 1 ; } while ( 1 ) { sprintf( buf , "client %s: line %d\0" , argv[1] , ii++ ) ; printf("%s\n" , buf ) ; re = send( socket1 , buf , strlen( buf ) + 1 , 0 ) ; printf("enter -1 for exit , other to continue\n" ) ; scanf("%d" , &cancel ) ; if( cancel == -1 ) break ; //Sleep( 10000 ) ; } if( socket1 >=0 ) closesocket( socket1 ) ; return 0; }
相关文章推荐
- C++socket客户端select异步连接发送接收数据
- Python使用封装类协程接收客户端数据,卡在接收函数,进不去
- Spark sql 使用jdbc/odbc Server连接出现新建的数据表多客户端没法共享
- 在阻塞式的tcp连接中使用recv接收数据未达到指定长度返回问题
- httpclient使用post方式发送json数据,以及服务端的接收
- Bootstrap table的使用,与后台数据连接,可自动翻页(客户端翻页)
- SBJSON的使用;OC中接收JSON 数据转到NSString;以及JSON数据和NSDictionary的区别;swift转OC
- windows socket简单使用--实现客户端链接服务端并发送和接收数据
- 关于使用nio实现广播数据给所有已连接客户端
- 使用TCP协议编写一个网络程序,设置服务器端的监听端口是8002,当与客户端建立连接后,服务器端向客户端发送数据“Hello, world”,客户端收到数据后打印输出。
- Spring JDBC-使用Spring JDBC获取本地连接对象以及操作BLOB/CLOB类型数据
- libcur设置接收数据的回调函数以及回调函数的使用
- ios客户端向服务器端发送数据以及接收数据要如何实现?
- [Socket网络编程]由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
- MFC(基于VS2013)连接下位机简单实例(下位机连接以及Socket数据发送接收)
- 你知道吗,如何使用select2插件实现下拉框一次性选多个值、以及数据的回显
- 使用TCP协议编写一个网络程序,设置服务器端的监听端口是8002,当与客户端建立连接后,服务器端向客户端发送数据“Hello, world”,客户端收到数据后打印输出
- C++ Builder XE8 安卓开发之使用TIdThreadComponent控件接收客户端的数据
- winsock简单使用(采用select轮询方式,从客户端获取数据)
- ios socket第三方框架 AsyncSocket使用简介,连接,心跳,断线,数据发送与接收