c - 在线程中使用select()不会对操作系统主机断开连接使用react

标签 c multithreading sockets select disconnected

我有主服务器代码,它使用select并等待主机 Activity 。
我也有全局结构,该结构存储所有客户端及其套接字。

//旧代码

当来自客户端阵列的主机之一断开连接时,主线程中的Select会自我取消阻止。然后,我尝试读取数据,当它为0时,客户端断开连接。为什么在Thread中进行选择不能以相同的方式工作?当客户端交换数据时,它工作完美,但是当其中一个客户端断开连接时,则没有任何 react 。

编辑。

抱歉,我之前已经发布了无法编译的代码。我的想法是,如果我对客户的处理想法是正确的,并且该想法应该可行,则只是获取信息。我创建了一个简单的示例,现在它可以工作了。因此,我必须查看我的原始代码。

工作示例:

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <pthread.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include <sys/wait.h>

#define MAXCLIENTS 1000
#define FRAMESIZE 40

struct Client
{
  int socket;
  char state;
};
struct Client clients[2];

struct ThreadArgs
{
  int srcClientIdx;
  int dstClientIdx;
};

int portNumber=8090;

void * SocketThread(void *args)
{
   printf("New thread created.\n");
   struct ThreadArgs *threadArgs = (struct ThreadArgs*)args;
   int sidx = threadArgs->srcClientIdx;
   int didx = threadArgs->dstClientIdx;
   int srcSocket = clients[sidx].socket;
   int dstSocket = clients[didx].socket;

   fd_set readfds;
   struct timeval timeout;

   while(1)
   {
      FD_ZERO(&readfds);
      FD_SET(srcSocket, &readfds);
      FD_SET(dstSocket, &readfds);

      printf("Waiting for activities in thread.\n");

      timeout.tv_sec = 60;
      timeout.tv_usec = 0;
      int activity = select(MAXCLIENTS+1, &readfds , NULL , NULL , &timeout);
      if ((activity < 0) && (errno!=EINTR))
         printf("Activity error.\n");
      else if(activity == 0)
         printf("Activity timeout.\n");

      if (FD_ISSET(srcSocket, &readfds))
      {
         unsigned char buffer[FRAMESIZE];
         int bytesCnt = read(srcSocket, buffer, sizeof(buffer));
         if(bytesCnt == 0)
         {
           printf("Client%d disconnected.\n",sidx);
           clients[sidx].state = 0;
           clients[sidx].socket = -1;
           pthread_exit(NULL);
         }
         else
           printf("Client%d activity.\n",sidx);
      }

      if (FD_ISSET(dstSocket, &readfds))
      {
         unsigned char buffer[FRAMESIZE];
         int bytesCnt = read(dstSocket, buffer, sizeof(buffer));
         if(bytesCnt == 0)
         {
           printf("Client%d disconnected.\n",didx);
           clients[didx].state = 0;
           close(clients[didx].socket);
           clients[didx].socket = -1;
           pthread_exit(NULL);
         }
         else
           printf("Client%d activity.\n",didx);
      }

   }
 }

 int ConfigureTCPIPconnection(int socket,struct sockaddr_in *serverAddr)
 {
   // Address family = Internet
   serverAddr->sin_family = AF_INET;
   //Set port number, using htons function to use proper byte order
   serverAddr->sin_port = htons(portNumber);
   //Incoming addresses
   serverAddr->sin_addr.s_addr = INADDR_ANY;

   //Set all bits of the padding field to 0
   memset(serverAddr->sin_zero, '\0', sizeof serverAddr->sin_zero);

   //Bind the address struct to the socket
   if(bind(socket, (struct sockaddr *)serverAddr, sizeof(struct sockaddr)) < 0)
   {
     printf("Binding failed. %s\n",strerror(errno));
     return 1;
   }

   printf("Bind sucessfull.\n");
   return 0;
 }

int CheckSocketActivity(fd_set *readfds)
{
   int activity = select( MAXCLIENTS + 1 , readfds , NULL , NULL , NULL);
   if ((activity < 0) && (errno!=EINTR))
      return 1;
   return 0;
}

int main(int argc, char *argv[])
{
  fd_set readfds;
  int serverSocket,newSocket;
  pthread_t td; //thread descriptor
  struct sockaddr_in serverAddr, newAddr={0};
  socklen_t addr_size;

  clients[0].state = 0;
  clients[0].socket = -1;
  clients[1].state = 0;
  clients[1].socket = -1;

  if((serverSocket = socket(PF_INET, SOCK_STREAM, 0)) == 0)
  {
    printf("Server socket creation failed.\n");
    exit(1);
  }

  if(ConfigureTCPIPconnection(serverSocket,&serverAddr))
  {
    printf("Binding failed.\n");
    exit(2);
  }

  if(listen(serverSocket,MAXCLIENTS))
  {
    printf("Listen error.\n");
    exit(3);
  }

  printf("Listening...\n");

  while(1)
  {
    FD_ZERO(&readfds); //clear fd set
    FD_SET(serverSocket, &readfds); //add server socket to fd set
    if(clients[0].state == 1)
      FD_SET(clients[0].socket, &readfds); //add active clients to fd set
    if(clients[1].state == 1)
      FD_SET(clients[1].socket, &readfds);

    printf("Waiting for activities.\n");

    if(!CheckSocketActivity(&readfds))
    {
      if(FD_ISSET(serverSocket, &readfds))
      {
        if((newSocket = accept(serverSocket, (struct sockaddr *)&newAddr, (socklen_t*)&addr_size))<0) //create new socket
          printf("New socket error. %s\n",strerror(errno));
        else
        {
          printf("New socket connected.\n");
          if(clients[0].state == 0)
          {
            printf("Client0 added.\n");
            clients[0].state = 1;
            clients[0].socket = newSocket;
          }
          else if(clients[1].state == 0)
          {
            printf("Client1 added.\n");
            clients[1].state = 1;
            clients[1].socket = newSocket;
          }
        }
      }
        else
        {
           for(int i=0;i<2;i++)
           {
              int srcSock = clients[i].socket;
              if (FD_ISSET(srcSock, &readfds))
              {
                 unsigned char buffer[FRAMESIZE];
                 int bytesCnt = read(srcSock, buffer, sizeof(buffer));
                 if(bytesCnt == 0)
                 {
                   printf("Client%d disconnected.\n",i);
                   clients[i].state = 0;
                   close(clients[i].socket);
                   clients[i].socket = -1;
                 }
                 else
                 {
                   if(clients[0].state == 1 && clients[1].state == 1)
                   {
                      int srcIndex,dstIndex;
                      //some other stuff
                      clients[0].state = 2;
                      clients[1].state = 2;
                      if(i == 0)
                      {
                        srcIndex = 0;
                        dstIndex = 1;
                      }
                      else
                      {
                        srcIndex = 1;
                        dstIndex = 0;
                      }
                      printf("Creating new thread.\n");
                      struct ThreadArgs threadArgs = {srcIndex,dstIndex};
                      if(pthread_create(&td, NULL, SocketThread, &threadArgs) != 0)
                         printf("Failed to create thread.\n");
                      if (pthread_detach(td))
                         printf("Thread detach error.\n");
                    }
                    else
                      printf("Two clients required for creating thread.\n");
                 }
              }
           }
        }
     }
  }
}

最佳答案

我假设您发布了确实要处理的代码,因为发布的代码不应该编译。

  • 更正1(可能不是问题的根源)

  • select()手册页:
    void FD_CLR(int fd, fd_set *set);
    int  FD_ISSET(int fd, fd_set *set);
    void FD_SET(int fd, fd_set *set);
    void FD_ZERO(fd_set *set); 
    

    所有FD_*()宏都带有fd_set*参数。在main()中,您已经在少数地方传递了fd_set而不是fd_set*
  • 更正2(可能是问题的根源)

  • SocketThread()中,这段代码可能是导致此问题的原因:
      if (FD_ISSET(dstSocket, &readfds))
       {
          unsigned char buffer[FRAMESIZE];
          bytesCnt = read(srcSock, buffer, sizeof(buffer));
          if(bytesCnt == 0)
             **//this is not detected**
          else
            //any other activities are detected
       }
    

    您可能需要read(dstSocket, buffer, sizeof(buffer));

    关于c - 在线程中使用select()不会对操作系统主机断开连接使用react,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62242370/

    相关文章:

    c++ - gametutorials.com 问题和评论 DirectX 教程

    c# - C# 中的 C 位域

    c - libpcap 从 AF_LINK sockaddr_dl (OSX) 获取 MAC

    无法创建可从我的程序访问的 C 头文件

    java - Java线程什么时候空闲?

    java - CompletableFuture : after async call, 当前线程中的处理结果

    python - 定时器中断线程python

    java - 强制 socket.connect 在确定连接不可用之前等待特定时间

    java - java中通过socket的Unicode文本

    python - UDP Socketserver - 通过同一个套接字发送数据(不可能?)