socket select用法:100行代码实现网络数据转发程序

socket select用法:100行代码实现网络数据转发程序 « Xiaoxia[PG]

socket select用法:100行代码实现网络数据转发程序

无聊学习一下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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值