【问题标题】:C/Unix sockets: Server closes right after one client doesC/Unix 套接字:服务器在一个客户端关闭后立即关闭
【发布时间】:2017-05-20 12:07:21
【问题描述】:

(这个问题是thisdreadful question的续集)

我已经设法用我损坏的代码解决问题,并让它使用线程为多个客户端工作。

服务器:

#define SOCK_PATH "avg_socket"

int numofclients=0;
int numofrequests=0;
pthread_mutex_t MUT=PTHREAD_MUTEX_INITIALIZER;

void *find_average (void *arg)
{
        int so = (int) arg;
        int done;

        printf("Connected.\n");

            done = 0;

            do {
                int i=0;
                int numofelements=0;
                int sum=0;
                float avg;

               ...
               ...
               ...


                pthread_mutex_lock(&MUT);
                        numofrequests++;
                pthread_mutex_unlock(&MUT);

                printf("\n\nNumber of requests: %d \n", numofrequests);
                printf("Number of clients: %d \n", numofclients);    

            } while (!done);

         close(so);
         pthread_exit(NULL);
}

int main(void)
    {
        int s, s2, i, t, len;
        struct sockaddr_un local, remote;
        pthread_t thread[50];

        if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(1);
        }

        local.sun_family = AF_UNIX;
        strcpy(local.sun_path, SOCK_PATH);
        unlink(local.sun_path);
        len = strlen(local.sun_path) + sizeof(local.sun_family);
        if (bind(s, (struct sockaddr *)&local, len) == -1) {
            perror("bind");
            exit(1);
        }

        if (listen(s, 5) == -1) {
            perror("listen");
            exit(1);
        }

        i=0;

        for(;;) {
            printf("Waiting for a connection...\n");
            t = sizeof(remote);
            if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
                perror("accept");
                exit(1);
            }
            numofclients++; //counting the number of clients
            pthread_create(&(thread[i++]), NULL, find_average, (void *)s2);
         }

        return 0;
    }

客户:

#define SOCK_PATH "avg_socket"

    int main(void)
    {
        int i, s, t, len, done;

        struct sockaddr_un remote;

        if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(1);
        }

        printf("Trying to connect...\n");

        remote.sun_family = AF_UNIX;
        strcpy(remote.sun_path, SOCK_PATH);
        len = strlen(remote.sun_path) + sizeof(remote.sun_family);
        if (connect(s, (struct sockaddr *)&remote, len) == -1) {
            perror("connect");
            exit(1);
        }

        printf("Connected.\n");

        done = 0;
        int yesorno=1;

        do {
            float avg;
            char seq[100];
            char str[100];
            char avgstring[200];


            printf("Give the sequence of integers: \n");
            fgets(seq, 100, stdin);

            ...
            ...
            ...

            printf("\nWanna Continue? (1/0) :");
            scanf("%d", &yesorno);
            getchar();

            if(!yesorno)
                done=1;

         } while (!done);

        close(s);

        return 0;
    }

(有兴趣的人可以使用完整代码here

但是现在,每次我关闭来自一个客户端的连接时,服务器也会关闭。

如上所示,客户端 3 关闭与服务器的连接,服务器本身同时关闭,而不是等待连接或客户端请求。

在我看来,服务器上的close(so) 似乎有些不对劲。我试图将它移动到循环中,例如here,但这只会在服务器上造成无限循环。

所以问题是,如何在客户端关闭时保持多线程服务器处于活动状态?

【问题讨论】:

  • 我建议使用调试器,跟踪代码以了解实际情况。
  • 对于recv() 失败的两个极端情况(这会导致它返回-1 或返回100 此代码int checkresponse=recv(s, str, 100, 0); str[checkresponse]='\0'; 写出str 的边界,并这样做调用臭名昭著的未定义行为。从那时起,任何事情都可能发生。你想解决这个问题。

标签: c multithreading sockets


【解决方案1】:
            char arr[100];
            recv(so, arr, 100, 0);

            int *array;    
            array=(int *)calloc(1, 100);

            char *p=strtok(arr, " ");

strtok 函数需要一个字符串作为其第一个参数。通过网络连接接收的任意字节集合不是字符串。

在一个相关问题中,您丢弃了recv 的结果。所以你没有办法知道你什么时候失败了。更糟糕的是,如果你成功了,你不知道你收到了多少字节!你怎么期待strtok 知道?魔法?

【讨论】:

  • 真的不确定这是否真的是一个有见地的观察,还是因为没有使用if 来代替recv 并转换arr
  • 对recv 使用“if”也是不正确的。 recv() 返回的值必须得到正确和完整的处理(所有系统调用都应该如此,但 recv 属于它自己的一个类)。
  • 恐怕无法理解和正确处理 TCP 的流传输性质在 C TCP 问题中很普遍,就像滥用需要带有 NUL 终止符的 char 数组的 C 库调用一样。 David 不是“挑剔”,recv() 返回的值是确定已收到多少字节(如果有的话)的唯一方法。
  • @Coursal 因为您将其视为字符串而导致接收缓冲区溢出是崩溃的常见原因,并且很可能是导致他崩溃的原因。另一种可能性是他的内存不足并推迟了从calloc 返回的NULL,因为他在一个循环中旋转,该循环在连接关闭时进行分配。所有这些都归结为我解释的问题。
  • @DavidSchwartz 如果我误解了请纠正我,您建议检查recv() 中的arr 字节集合,然后将arr 转换为字符串?
猜你喜欢
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
相关资源
最近更新 更多