侦听两个不同端口的 TCP 服务器

Posted

技术标签:

【中文标题】侦听两个不同端口的 TCP 服务器【英文标题】:TCP server that listen on two different ports 【发布时间】:2015-09-23 14:00:07 【问题描述】:

我有一个监听两个不同端口的 TCP 服务器。我创建了两个不同的套接字,一个在端口 8888 上,一个在端口 6634 上。我侦听这些端口,然后在 FD_SET 中添加两个套接字并将它们传递给 select() 函数... 当套接字准备好读取时,我会检查 FD_ISSET 以查看我在哪个端口上有要读取的消息。

当我连接到端口 8888 时,构想成功,我可以向服务器发送并接收......当我 ctrl+c 客户端时,选择函数再次返回 1,现在我的 accept() 失败.. . 当我在端口 6634 上做同样的事情时,一切正常......代码在 select() 处停止并等待套接字准备好读取!

谁能告诉我为什么会这样?

看看我在附件中的代码

    int main()
    
        SOCKET          conn_request_skt;   /* socket where connections are accepted */
        char            buf[RBUFLEN], buf1[RBUFLEN];        /* reception buffer */
        uint16_t        lport_n, lport_h, lport_n1, lport_h1;   /* port where the server listens (net/host byte ord resp.) */
        int         bklog = 2;      /* listen backlog */
        SOCKET          s,s1;           
        int         result, n;
        socklen_t addrlen;
        struct sockaddr_in  saddr, caddr;       /* server and client address structures */ 
        int optval,childpid,i; /* flag value for setsockopt */
        int connectcnt; /* number of connection requests */
        fd_set readfds;

        /* Initialize socket API if needed */
        SockStartup();

        /* input server port number */
        lport_h=6634;
        lport_n = htons(lport_h);
        lport_h1=8888;
        lport_n1 = htons(lport_h1);

        /* create the socket */
        printf("Creating first socket\n");
        s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == INVALID_SOCKET)
            err_fatal("socket() failed");
        printf("done, socket number %u\n",s);

        /* bind the socket to any local IP address */
        saddr.sin_family      = AF_INET;
        saddr.sin_port        = lport_n;
        saddr.sin_addr.s_addr = INADDR_ANY;
        showAddr("Binding to address first socket", &saddr);
        result = bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
        if (result == -1)
            err_fatal("bind() failed");
        printf("done.\n");

        printf("Creating second socket\n");
        s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s1 == INVALID_SOCKET)
            err_fatal("socket() failed");
        printf("done, socket number %u\n",s1);

        /* bind the socket to any local IP address */

        saddr.sin_port=lport_n1;

        showAddr("Binding to address second socket", &saddr);
        result = bind(s1, (struct sockaddr *) &saddr, sizeof(saddr));
        if (result == -1)
            err_fatal("bind() failed");
        printf("done.\n");


        /* listen */
        printf ("Listening at socket %d with backlog = %d \n",s,bklog);
        result = listen(s, bklog);
        if (result == -1)
            err_fatal("listen() failed");
        printf("done.\n");

        printf ("Listening at socket %d with backlog = %d \n",s1,bklog);
        result = listen(s1, bklog);
        if (result == -1)
            err_fatal("listen() failed");
        printf("done.\n");
for (;;)
    


        FD_ZERO(&readfds);          /* initialize the fd set */
        FD_SET(s, &readfds);
        FD_SET(s1, &readfds); /* add socket fd */
        printf("here \n");

        printf("result bifore select is %d \n", result);
        result=select(s1+1, &readfds, 0, 0, 0);

        printf("result after select is %d \n", result);

        if(result<0)
            
                err_fatal("select() failed");

            
        if(result>0)
        

            if(FD_ISSET(s,&readfds))
            

                conn_request_skt=s;
                /* accept next connection */
                addrlen = sizeof(struct sockaddr_in);
                s = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
                if (s == INVALID_SOCKET)
                err_fatal("accept() failed");
                showAddr("Accepted connection from", &caddr);
                printf("new socket: %u\n",s);
                /* serve the client on socket s */
                for (;;)
                
                    n=recv(s, buf, RBUFLEN-1, 0);
                    if (n < 0)
                    
                        printf("Read error\n");
                        closesocket(s);
                        printf("Socket %d closed\n", s);
                        break;
                    
                    else if (n==0)
                    
                        printf("Connection closed by party on socket %d\n",s);
                        //closesocket(s);
                        break;
                    
                    else
                    
                        printf("Received line from socket %03d :\n", s);
                        buf[n]=0;
                        printf("[%s]\n",buf);
                        if(writen(s, buf, n) != n)
                        printf("Write error while replying\n");
                        else
                        printf("Reply sent\n");
                       
                
            


            if(FD_ISSET(s1,&readfds))
            
                conn_request_skt=s1;
                /* accept next connection */
                addrlen = sizeof(struct sockaddr_in);
                printf("bifore accept! \n");
                s1 = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
                if (s1 == INVALID_SOCKET)
                err_fatal("accept() failed");
                showAddr("Accepted connection from", &caddr);
                printf("new socket: %u\n",s1);
                /* serve the client on socket s */
                for (;;)
                
                    n=recv(s1, buf, RBUFLEN-1, 0);
                    if (n < 0)
                    
                        printf("Read error\n");
                        closesocket(s1);
                        printf("Socket %d closed\n", s1);
                        break;
                    
                    else if (n==0)
                    
                        printf("Connection closed by party on socket %d\n",s1);
                        //closesocket(s);
                        break;
                    
                    else
                    
                        printf("Received line from socket %03d :\n", s1);
                        buf[n]=0;
                        printf("[%s]\n",buf);
                        if(writen(s1, buf, n) != n)
                        printf("Write error while replying\n");
                        else
                        printf("Reply sent\n");
                       
                
            
        
    

【问题讨论】:

【参考方案1】:

第一个侦听器套接字是通过以下方式创建的:

s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

然后数据套接字被接受:

 conn_request_skt=s;
 s = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);

看到了吗?下一个循环,当您要在侦听器套接字上进行选择时,s 不再保留该套接字,而是(关闭的)数据套接字。

解决方案是为侦听器套接字和数据套接字使用不同的变量(conn_request_skt 只是混淆了问题)。

【讨论】:

【参考方案2】:

您正在用 accept() 调用的结果覆盖您的套接字变量 s1。所以 s1 现在包含您实际从中读取的套接字的描述符。然后你关闭那个套接字。但是在主循环的下一个循环中,您检查该(现已关闭)描述符的可读性,这不起作用。

我相信在这种情况下最好不要重用变量。为实际的连接socket使用一个新变量,这样就可以在s1中保留原来的监听socket。

【讨论】:

以上是关于侦听两个不同端口的 TCP 服务器的主要内容,如果未能解决你的问题,请参考以下文章

在同一端口上侦听 TCP 和 UDP 请求

在两个不同的端口上运行 Tomcat 服务器

一个完整的TCP连接

一个完整的TCP连接

C# TCP 在同一个本地端口上侦听和连接

如何确定正在侦听端口 80 的服务器