select回声Server端实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<sys/select.h>

void error_handling(char *message);

#define BUFF_SIZE 32

int main(int argc, char *argv[])
{
    int server_sock;
    int client_sock;

    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    socklen_t client_addr_size;

    char buff[BUFF_SIZE];
    fd_set reads, reads_init;
    struct timeval timeout, timeout_init;

    int str_len, i, fd_max, fd_num;

    if(argc!=2){ //命令行中启动服务程序仅限一个参数:端口号
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    //调用socket函数创建套接字
    server_sock = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == server_sock){
        error_handling("socket() error.");
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(argv[1]));

    //调用bind函数分配IP地址和端口号
    if( -1 == bind( server_sock, (struct sockaddr*)&server_addr, 
                sizeof(server_addr)) ){
        error_handling("bind() error");
    }

    //监听端口的连接请求,连接请求等待队列size为5
    if( -1 == listen(server_sock, 5) ){
        error_handling("listen() error");
    }

    //register fd_set var
    FD_ZERO(&reads_init);
    FD_SET(server_sock, &reads_init);//monitor socket: server_sock
    FD_SET(0, &reads_init);// stdin also works
    fd_max = server_sock;
    //
    timeout_init.tv_sec = 5;
    timeout_init.tv_usec= 0;

    while(1){
        //调用select之后,除发生变化的文件描述符对应的bit,其他所有位置0,所以需用保存初值,通过复制使用
        reads = reads_init;
        //调用select之后,timeval成员值被置为超时前剩余的时间,因此使用时也需要每次用初值重新初始化
        timeout = timeout_init;
        fd_num = select(fd_max+1, &reads, NULL, NULL, &timeout);
        if(fd_num < 0){
            fputs("Error select()!", stderr);
            break;
        }else if(fd_num == 0){
            puts("Time-out!");
            continue;
        }
        for(i=0; i<=fd_max; i++){
            if(FD_ISSET(i, &reads)){
                if(i == server_sock){//connection request!
                    //接受连接请求
                    client_addr_size = sizeof(client_addr);
                    client_sock = accept( server_sock, (struct sockaddr*)&client_addr, &client_addr_size );
                    //accept函数自动创建数据I/0 socket
                    if(-1 == client_sock){
                        error_handling("accept() error");
                        //健壮性不佳,程序崩溃退出
                    } else{
                        //注册与客户端连接的套接字文件描述符
                        FD_SET(client_sock, &reads_init);
                        if(fd_max < client_sock) fd_max = client_sock;
                        printf("Connected client : %d\n", client_sock);
                    }
                }else{//read message!
                    str_len = read(i, buff, BUFF_SIZE);
                    if(str_len){//echo to client
                        buff[str_len] = 0;
                        printf("Message from client %d: %s", i, buff);
                        write(i, buff, str_len);
                    }else{ //close connection
                        FD_CLR(i, &reads_init);
                        close(i);
                        printf("Disconnected client %d!\n", i);
                    }
                }//end of i==|!=server_sock
            }//end of if(FD_ISSET)
        }//end of while

    }//end of for

    //断开连接,关闭套接字
    close(server_sock);

    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(EXIT_FAILURE);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值