使用socket编程(一) 中的主程序,存在以下两个问题:

    1). 有时候重启会出错,提示“bind error: Address already in use”。解决此问题用到setsockopt()函数;

       2).  同时只能处理单用户请求;

下面进一步完善”socket编程(一)“的主程序,使用它能同时处理多个客户端请求。

主要技巧是使用fork()产生子进程,让子进程去处理客户端请求。

#include "../apue.h"

int main(void){
        int listenfd;
        listenfd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(listenfd < 0)
                err_exit("listen error");

        struct sockaddr_in servaddr;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(5188);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        //servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        //inet_aton("127.0.0.1", $servaddr.sin_addr);

        int on=1;
        if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))<0)
                err_exit("setsockopt error");

        if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))<0)
                err_exit("bind error");

        if(listen(listenfd, SOMAXCONN)<0)
                err_exit("listen error");

        struct sockaddr_in peeraddr;
        socklen_t peerlen = sizeof(peeraddr);
        int conn;
        pid_t pid;
        while (1){
                if((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen))<0)
                        err_exit("accept error");
                printf("ip=%s,port=%d\n", inet_ntoa(peeraddr.sin_addr), peeraddr.sin_port);

                pid = fork();
                if(pid==-1)
                        err_exit("fork error");
                if(pid==0){
                        close(listenfd);
                        while(1){
                        char buf[1024];
                        int ret;
                    memset(buf, 0, sizeof(buf));
                    ret = read(conn, buf, sizeof(buf));
                                if(ret==0){
                                        printf("client close\n");
                                        break;
                                }
                                else if(ret==-1)
                                        err_exit("ret error");
                    fputs(buf, stdout);
                    write(conn, buf, ret);
                                }
                                exit(EXIT_SUCCESS);
                }else{
                        close(conn);
                }

        }
        return 0;
}