首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用setsockopt(SO_REUSEADDR)?

如何使用setsockopt(SO_REUSEADDR)?
EN

Stack Overflow用户
提问于 2014-06-13 06:36:23
回答 3查看 150K关注 0票数 69

我在树莓派上运行我自己的http服务器。问题是,当我停止程序并重新启动它时,端口不再可用。有时,当我收到大量请求时,也会遇到同样的问题。

我想使用SO_REUSEADDR,这样我就可以继续使用端口,即使发生错误,但没有幸运地设置它。下面是我的代码。

我得到的错误是“绑定错误:地址已在使用中”。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    printf("Starting Listener\n");
     int sockfd, newsockfd, portno;
     socklen_t clilen;
     char buffer[256];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     if (argc < 2) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");

     printf("about to listen\n");
     listen(sockfd,5);
     printf("finished listening\n");
     clilen = sizeof(cli_addr);
     printf("About to accept\n");

     int i;
     for(i=0; i<100; i++){
         newsockfd = accept(sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);

         if (newsockfd < 0) 
             error("ERROR on accept");
         bzero(buffer,256);
         n = read(newsockfd,buffer,255);
         if (n < 0) error("ERROR reading from socket");
         printf("Here is the message: %s\n",buffer);
         n = write(newsockfd,"I got your message",18);
         if (n < 0) error("ERROR writing to socket");
         close(newsockfd);
     }
     close(sockfd);
     return 0; 
}
EN

回答 3

Stack Overflow用户

发布于 2014-06-13 06:40:39

之后:

代码语言:javascript
复制
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) 
    error("ERROR opening socket");

您可以添加(使用标准C99 compound literal支持):

代码语言:javascript
复制
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)
    error("setsockopt(SO_REUSEADDR) failed");

或者:

代码语言:javascript
复制
int enable = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
    error("setsockopt(SO_REUSEADDR) failed");
票数 95
EN

Stack Overflow用户

发布于 2014-08-08 06:45:26

根据libc版本的不同,可能需要同时设置SO_REUSEADDR和SO_REUSEPORT套接字选项,如socket(7)文档中所述:

SO\_REUSEPORT (since Linux 3.9) Permits multiple AF\_INET or AF\_INET6 sockets to be bound to an identical socket address. This option must be set on each socket (including the first socket) prior to calling bind(2) on the socket. To prevent port hijacking, all of the processes binding to the same address must have the same effective UID. This option can be employed with both TCP and UDP sockets.

由于此套接字选项出现在内核3.9和raspberry使用的3.12.x中,因此需要设置SO_REUSEPORT。

您可以在调用bind之前设置这两个选项,如下所示:

代码语言:javascript
复制
    int reuse = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
        perror("setsockopt(SO_REUSEADDR) failed");

#ifdef SO_REUSEPORT
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) 
        perror("setsockopt(SO_REUSEPORT) failed");
#endif
票数 43
EN

Stack Overflow用户

发布于 2018-08-13 16:13:30

我认为你应该使用SO_LINGER选项(超时为0)。在这种情况下,您的连接将在关闭程序后立即关闭;下一次重新启动将能够再次绑定。

示例:

代码语言:javascript
复制
linger lin;
lin.l_onoff = 0;
lin.l_linger = 0;
setsockopt(fd, SOL_SOCKET, SO_LINGER, (const char *)&lin, sizeof(int));

参见定义:http://man7.org/linux/man-pages/man7/socket.7.html

代码语言:javascript
复制
SO_LINGER
          Sets or gets the SO_LINGER option.  The argument is a linger
          structure.

              struct linger {
                  int l_onoff;    /* linger active */
                  int l_linger;   /* how many seconds to linger for */
              };

          When enabled, a close(2) or shutdown(2) will not return until
          all queued messages for the socket have been successfully sent
          or the linger timeout has been reached.  Otherwise, the call
          returns immediately and the closing is done in the background.
          When the socket is closed as part of exit(2), it always
          lingers in the background.

更多关于SO_LINGER的信息:TCP option SO_LINGER (zero) - when it's required

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24194961

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档