无聊学习一下select+blocking socket的用法。不使用多线程+blocking socket的方法。
程序从本地1998端口转发到221.130.162.247的80端口:
#include <stdio.h> #include <winsock.h> #include <wininet.h> WSADATA wsaData; #define client_count 100 int clients[client_count] = {0}; int remotes[client_count] = {0}; static void remove_client(int i) { shutdown(clients[i], SD_RECEIVE); closesocket(clients[i]); shutdown(remotes[i], SD_RECEIVE); closesocket(remotes[i]); clients[i] = remotes[i] = 0; } static int get_client() { int i; for( i = 0; i<client_count; i++) if(!clients[i]) return i; return 0; } int main(int argc, char **argv) { fd_set fdreads, fdwrites; const int buf_size = 1024*32; char buf[buf_size]; int ret = WSAStartup(MAKEWORD(2,1), (WSADATA*)&wsaData ); if(ret!=0) perror( "failed to initialize win32 WSA" ); int sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); struct sockaddr_in addr = {0}; struct sockaddr_in remote_addr = {0}; addr.sin_family = remote_addr.sin_family = PF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons( 1998 ); remote_addr.sin_addr.s_addr = inet_addr("221.130.162.247"); remote_addr.sin_port = htons( 80 ); if( bind( sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in) ) < 0 ) perror("failed to bind socket"); listen( sock , 5); printf("listen\n"); for(;;){ int i, j, k; FD_ZERO(&fdreads); FD_SET( sock, &fdreads); for( i=0; i<client_count; i++) if(clients[i]){ FD_SET( clients[i], &fdreads ); FD_SET( remotes[i], &fdreads ); } ret = select(0, &fdreads, 0, 0, 0); printf("select ret=%d\n", ret); switch(ret){ case -1: perror("error"); break; case 0: perror("timeout?"); break; default: if(FD_ISSET(sock, &fdreads)){ int j = get_client(); printf("accept %d\n", j); int len = sizeof(struct sockaddr_in); clients[j] = accept(sock, 0, 0); remotes[j] = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); addr.sin_port = htons( 0 ); if( bind( remotes[j], (struct sockaddr*)&addr, sizeof(struct sockaddr_in) ) < 0 ) exit(errno); if( connect( remotes[j], (struct sockaddr*)&remote_addr, sizeof(struct sockaddr_in) ) < 0) exit(errno); } for( i=0; i<client_count; i++){ if(!clients[i]) continue; if(FD_ISSET(clients[i], &fdreads) ){ int ret = recv(clients[i], buf, buf_size, 0); printf("client_read_ret=%d\n", ret); if( ret > 0 ) send( remotes[i], buf, ret, 0 ); if( ret <= 0 ) remove_client(i); } if(FD_ISSET(remotes[i], &fdreads) ){ int ret = recv(remotes[i], buf, buf_size, 0); printf("remote_read_ret=%d\n", ret); if( ret > 0 ) send( clients[i], buf, ret, 0 ); if( ret <= 0 ) remove_client(i); } } } } return 0; }
累了,找个沙发坐下,,
板凳。
select效率低下,已经很少人用了。
除了select,还有啥好方法能单个线程管理多个socket? 如果1000个socket呢?epoll只能在linux,iocp只能在windows?最好跨平台吧。。。
Pingback引用通告: I/O复用之使用select完成端口转发功能 | 秣马儿的博客