2

我有主服务器代码,它使用选择并等待主机活动。我还有全局结构,它存储所有客户端及其套接字。

//旧代码

当来自客户端阵列的主机之一断开连接时,在主线程中选择会解除阻塞。然后我尝试读取数据,当它为0时,客户端断开连接。为什么在 Thread 中选择不能以相同的方式工作?当客户端交换数据时它工作得很好,但是当其中一个客户端断开连接时没有反应。

编辑。

对不起,我之前发布了无法编译的代码。这个想法是,如果我对客户处理的想法是正确的并且这个想法是否可行,只是为了获取信息。我创建了简单的示例,现在它可以工作了。所以,我必须检查我的原始代码。

工作示例:

#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");
                 }
              }
           }
        }
     }
  }
}
4

2 回答 2

1

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

  • 更正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));.

于 2020-06-07T19:36:47.627 回答
0

你说:

当来自客户端阵列的主机之一断开连接时,在主线程中选择会解除阻塞。然后我尝试读取数据,当它为0时,客户端断开连接。为什么在线程中选择不以相同的方式工作?当客户端交换数据时它工作得很好,但是当其中一个客户端断开连接时没有反应。

请不要说客户端如何断开连接。它只是关闭套接字吗?它会关机吗?我在套接字上看不到任何close(2)内容,那么您为什么知道谁在关闭连接(或调用shutdown(2)以指示连接中不会出现更多数据)?

通常,连接会阻塞,直到您收到一些数据...接收 0 数据意味着没有数据到达,或者在select(2)调用选择了一个不再显示数据的套接字描述符之后,您关闭了套接字。但这必须在某个地方关闭,并且您既不显示close(2)也不显示shutdown(2)。您也没有描述在套接字上检测到的内容。如果您从select(2)文件描述符中醒来,并且读取的结果不是0读取返回的值是什么?您是否知道这-1是其中一种可能的值,这意味着您有读取错误?你检查select返回的值吗?(在超时时,我的记忆告诉我select(0)返回 0,所以你在检查超时吗?)

下次请提供一个完整且可验证的示例。您发布的代码在没有大量贡献的情况下无法运行,因此问题只能在您身边重现。查看此页面以了解有关如何在 StackOverflow 中发布代码的信息。

于 2020-06-08T19:52:13.543 回答