无聊学习一下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完成端口转发功能 | 秣马儿的博客