C套接字程序示例 - 绑定错误:已在使用中

时间:2014-11-27 09:44:26

标签: c linux sockets

我有以下使用Linux套接字的示例代码:

void serve_request(int newsockfd)
{
    char buffer[256];
    int n;  

    /*if connection established then start communicating*/
    bzero(buffer, 256);
    n=read(newsockfd, buffer, 255);
    if(n<0)
    {   
        perror("Error reading from socket");
    }
    printf("Here is the message: %s\n",buffer);

    /*write response to the client*/
    n=write(newsockfd,"I got your message", 18);
    if(n<0)
    {
        perror("Error writing to socket");
        exit(1);
    }
    //close(newsockfd);
}

int main(int argc, char* argv)
{
    int sockfd, newsockfd, portno, clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;

    /*first call to socket function*/
    sockfd=socket(AF_INET, SOCK_STREAM, 0);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0);
    if(sockfd<0)
    {
        perror("Error opening socket");
        exit(1);
    }

    /*initialize socket structure*/
    bzero((char*)&serv_addr, sizeof(serv_addr));
    portno=5001;
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_addr.s_addr=INADDR_ANY;
    serv_addr.sin_port=htons(portno);

    /*now bind the host address using bind() call.*/
    if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr))<0)
    {
        perror("Error on binding");
        exit(1);
    }

    /*now start listening for the clients, here process will
    go in sleep mode and will wait for the incoming connection*/
    listen(sockfd, 5);
    clilen=sizeof(cli_addr);

    while(1)
    {
        /*accept actual connection from the client*/
        newsockfd=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
        if(newsockfd<0)
        {
            perror("Error on accept");
            exit(1);
        }   
        serve_request(newsockfd);
    }
    return 0;
}

这一切都很好。当我执行./a.out时,它启动套接字服务器并等待客户端。当我使用^C退出代码时,它会停止并返回提示。

但是,如果代码符合方法//close(newsockfd);中的最后一行(void serve_request(int newsockfd))未注释且客户端已经过去,则按下^C并再次调用服务器使用./a.out,它会显示Error on binding: Already in use

但是如果我编写了最后一行注释的代码,那么它工作正常,这意味着我可以立即用./a.out调用服务器并重新启动服务器,而无需像上一个案例那样等待一段时间

有人可以正确处理这个问题。 任何帮助深表感谢。谢谢。

3 个答案:

答案 0 :(得分:2)

当您打开套接字时,您分配了一个操作系统资源,并告诉您要重用套接字地址的o / s taht。

程序结束时没有自动清理。资源仍然分配。

取消注释close()并养成总是释放任何和所有资源的习惯,无论是内存,套接字,互斥体还是其他什么。

答案 1 :(得分:0)

你的问题与close()没什么关系。我怀疑你只是在调用之间等待了不同的时间。

1)您正在调用setsockopt错误,因此您尝试设置的选项无效。这是一个工作调用的例子:

int optval = 1; //enable option
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
    perror("setsockopt()");
    exit(1);
}

请注意,第三个参数是指针,对于任何合理的调用都是非可选的。 man setsockopt

  

大多数套接字级选项都使用int参数进行optval。对于   setsockopt(),参数应该是非零的          启用布尔选项,如果要禁用该选项,则为零。

2)您没有检查setsockopt()的返回值,因此找不到错误的希望很小。

3)完成后,请关闭newsockfd。在退出程序之前也要关闭sockfd

摘要:始终检查所有系统调用的返回值。为手册页上列出的所有返回值做好准备。在所有执行路径中释放/关闭所有已分配的资源。

PS。有点讽刺的是,编译代码所需的所有#include语句都是正确问题的一部分。

答案 2 :(得分:0)

您应该设置SO_REUSEADDR。你做到了 - 但不正确。这是如何正确地做到这一点:

    /* SO_REUSEADDR allows a new server to be started
     * on the same port as an existing server that is
     * bound to the wildcard address, as long as each
     * instance binds a different local IP address.
     * This is common for a site hosting multiple HTTP
     * servers using the IP alias technique */
    int reuseaddr_on = 1;
    if( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR,
            &reuseaddr_on, sizeof( reuseaddr_on)) < 0)
    {
        // log
    }

请务必在调用bind() 之前设置SO_REUSEADDR选项