当前位置: 首页 > 知识库问答 >
问题:

close()未正确关闭套接字

曾典
2023-03-14
Processing request for 21
Writing to 21
Closing 21
call close(21)
while(true) {
  client_socket = accept(incoming_socket, (struct sockaddr *)&client_addr, &client_len);
  if (client_socket == -1)
    continue;
  /*  insert into queue here for threads to process  */
}
/*  get client_socket from queue  */

/*  processing request here  */

/*  now set to blocking for write; was previously set to non-blocking for reading  */
int flags = fcntl(client_socket, F_GETFL);
if (flags < 0)
  abort();
if (fcntl(client_socket, F_SETFL, flags|O_NONBLOCK) < 0)
  abort();

server_write(client_socket, response_buf, response_length);
server_close(client_socket);
void server_write( int fd, char const *buf, ssize_t len ) {
    printf("Writing to %d\n", fd);
    while(len > 0) {
      ssize_t n = write(fd, buf, len);
      if(n <= 0)
        return;// I don't really care what error happened, we'll just drop the connection
      len -= n;
      buf += n;
    }
  }

void server_close( int fd ) {
    for(uint32_t i=0; i<10; i++) {
      int n = close(fd);
      if(!n) {//closed successfully                                                                                                                                   
        return;
      }
      usleep(100);
    }
    printf("Close failed for %d\n", fd);
  }
CURL *curl = curl_easy_init();
CURLcode res;
curl_easy_setopt( curl, CURLOPT_URL, url);
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_callback );
curl_easy_setopt( curl, CURLOPT_WRITEDATA, write_tag );

res = curl_easy_perform(curl);
shutdown(fd, SHUT_WR);                                                                                                                                            
char buf[64];                                                                                                                                                     
while(read(fd, buf, 64) > 0);                                                                                                                                         
/*  then close  */ 
struct linger l;
l.l_onoff = 1;
l.l_linger = 1;
if (setsockopt(client_socket, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
  abort();

共有1个答案

谭修然
2023-03-14

下面是我在许多类似UNIX的系统(例如SunOS 4、SGI IRIX、HPUX 10.20、CentOS 5、Cygwin)上使用过的关闭套接字的代码:

int getSO_ERROR(int fd) {
   int err = 1;
   socklen_t len = sizeof err;
   if (-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &len))
      FatalError("getSO_ERROR");
   if (err)
      errno = err;              // set errno to the socket SO_ERROR
   return err;
}

void closeSocket(int fd) {      // *not* the Windows closesocket()
   if (fd >= 0) {
      getSO_ERROR(fd); // first clear any errors, which can cause close to fail
      if (shutdown(fd, SHUT_RDWR) < 0) // secondly, terminate the 'reliable' delivery
         if (errno != ENOTCONN && errno != EINVAL) // SGI causes EINVAL
            Perror("shutdown");
      if (close(fd) < 0) // finally call close()
         Perror("close");
   }
}

但以上并不能保证发送任何缓冲写操作。

优雅的关闭:我花了大约10年的时间才弄清楚如何关闭一个插座。但在接下来的10年里,我只是懒洋洋地调用usleep(20000)来稍有延迟,以“确保”写入缓冲区在关闭前被刷新。这显然不是很高明,因为:

  • 大多数时间延迟太长。
  • 某些时间延迟太短--可能!
  • 这样的SIGCHLD信号可能会结束usleep()(但我通常调用usleep()两次来处理这种情况--黑客)。
  • 没有任何迹象表明这是否有效。但如果a)硬重置完全正常,和/或b)您可以控制链路的两侧,则这可能并不重要。

但做一个适当的冲水是惊人的困难。使用so_linger显然不是正确的方法;参见例如:

    null
bool haveInput(int fd, double timeout) {
   int status;
   fd_html" target="_blank">set fds;
   struct timeval tv;
   FD_ZERO(&fds);
   FD_SET(fd, &fds);
   tv.tv_sec  = (long)timeout; // cast needed for C++
   tv.tv_usec = (long)((timeout - tv.tv_sec) * 1000000); // 'suseconds_t'

   while (1) {
      if (!(status = select(fd + 1, &fds, 0, 0, &tv)))
         return FALSE;
      else if (status > 0 && FD_ISSET(fd, &fds))
         return TRUE;
      else if (status > 0)
         FatalError("I am confused");
      else if (errno != EINTR)
         FatalError("select"); // tbd EBADF: man page "an error has occurred"
   }
}

bool flushSocketBeforeClose(int fd, double timeout) {
   const double start = getWallTimeEpoch();
   char discard[99];
   ASSERT(SHUT_WR == 1);
   if (shutdown(fd, 1) != -1)
      while (getWallTimeEpoch() < start + timeout)
         while (haveInput(fd, 0.01)) // can block for 0.01 secs
            if (!read(fd, discard, sizeof discard))
               return TRUE; // success!
   return FALSE;
}
   if (!flushSocketBeforeClose(fd, 2.0)) // can block for 2s
       printf("Warning: Cannot gracefully close socket\n");
   closeSocket(fd);
   static void setFD_CLOEXEC(int fd) {
      int status = fcntl(fd, F_GETFD, 0);
      if (status >= 0)
         status = fcntl(fd, F_SETFD, status | FD_CLOEXEC);
      if (status < 0)
         Perror("Error getting/setting socket FD_CLOEXEC flags");
   }
 类似资料:
  • 我正在尝试使用Springboot反应式webclient进行HTTP调用。远程服务器错误导致连接关闭。 请查找以下使用Webclient进行rest调用的代码。 Webclient创建的代码: 第一次通话后,我收到以下日志: 当我在一段时间后(比如10分钟)拨打电话时,连接将变为非活动状态。我正在获取以下日志: 我发现连接没有正确返回到池。配置中是否缺少任何内容?我是否已正确关闭连接?我想这应该

  • 我正在处理一个需要使用jFileChooser Swing窗口的项目。当单击“取消”或“打开”时,窗口不会关闭。在查看了StackOverflow上的许多文章以及JFileChooser教程和文档之后,我不知道是什么导致了这个重复的问题。 我正在与NetBeans一起使用它的swing编辑器。我也在Eclipse中尝试了该程序作为测试,并收到了相同的结果。

  • 我的连接器类: 连接器。JAVA 这是我的DAO类(简化):UserDAO. java 在这里,我发现了关于Hikari的一些事实的问题: 您必须在HikariCP为您提供的连接实例上调用关闭() 可能是我的不起作用,因为它只是Hikari在方法中提供给我的连接的副本。

  • 有人能帮我吗?

  • 我使用来管理服务器端的套接字连接。如果服务器(tomcat)关闭,我如何确保任何活动的套接字连接被正确终止? 有好心的听众吗?或任何可以防止服务器关闭的拦截器,例如,如果在关闭期间有任何打开的套接字,则最多60秒;但同时关闭套接字,在关机期间不接受任何连接?

  • 我目前有一个简单的即时消息程序,它利用Java的Socket和ServerSocket类。它按预期运行,但当我尝试关闭连接时,它没有使用4路握手TCP断开来关闭连接。相反,它使用RST数据包突然关闭连接。 关闭连接的方法是从客户端向服务器发送一个字符串,服务器将把它识别为关闭连接的命令。然后,我在服务器上使用方法,在客户端上使用方法。 使用这些类正确关闭TCP连接的正确方式和/或事件顺序是什么?