为什么我的客户端-服务器解决方案的服务器会立即关闭连接?

Why does my server for my client-server solution shut down connection immediately?

我正在编写客户端-服务器解决方案。目标是远程连接到摄像头并在客户端接收其摄像头馈送。我为此使用 TCP 协议。是的,这是我第一次这样做。

客户端写在Java。这意味着它使用 BufferedReader.readLine()。是的,问题是它导致 null,我知道这意味着服务器关闭了连接。我也得到了一位高级编码员的证实。

服务器是用 C 语言编写的。我的问题是我找不到明显的原因来解释为什么它的代码会导致看似立即关闭连接。我发现了多个支持我已经在使用的方法的代码示例。

我想知道:

  1. 在这种情况下,BufferedReader 是否会导致 null 立即指示其他内容?
  2. 我的服务器代码中遗漏了什么,为什么它会关闭连接?

这是我的原始服务器代码(请参阅下面的更新):


#define _GNU_SOURCE -D

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <syslog.h>
#include <capture.h>
#include <sys/sendfile.h>
#include <pthread.h>
//define where the network camera is located
#define PORT_NUMBER 80
#define SERVER_ADDRESS "localhost"

void *msg_handler(void *);

//step 1
/* The server is supposed to send a list of available resolutions and frames per second, so the client can choose*/

//we create a handler to each client

void *client_handler(int server_socket)

{
    int serverSocket = *(int *)server_socket; // this is a pointer to the server socket
    char *message, cli_message[40000];
    message = capture_get_resolutions_list(0);     //list of available image resolutions;
    write(serverSocket, message, strlen(message)); //send to client the list of resolutions
    write(serverSocket, "\n", strlen("\n"));       //breaking line so the client can see the list
    memset(message, 0, strlen(message));           //resetting the message variable

    //variables related to the image
    media_stream *imageStream;

    recv(serverSocket, cli_message, 40000, 0); // receive information from client regarding resolution
    media_frame *imageFrame;
    void *data;
    size_t imageSize;
    int arrayRow = 0; //related to the data array - we need it if we want to loop later through the array

    //opening the stream in order to capture image
    imageStream = capture_open_stream(IMAGE_JPEG, cli_message);

    //send image to client with chosen resolution
    while (1) //condition always true, i.e. infinite loop
    {
        imageFrame = capture_get_frame(imageStream);
        data = capture_frame_data(imageFrame);

        imageSize = capture_frame_size(imageFrame);
        sprintf(message, "%zu\n", imageSize);          //converting the size to a char , and send to client
        write(serverSocket, message, strlen(message)); //sending the size to the client

        unsigned char arrayRow_data[imageSize];

        for (arrayRow = 0; arrayRow < imageSize; arrayRow++)
        {

            arrayRow_data[arrayRow] = ((unsigned char *)data)[arrayRow];
        }

        //try to send data to client ---> see the possible errors
        int sendDataError = write(serverSocket, arrayRow_data, sizeof(arrayRow_data));

        if (sendDataError < 0)
        {
            syslog(LOG_INFO, "oops, connection with client lost");
            break;
        }

        //restoring variables to ZERO
        memset(data, 0, sizeof(data));
        memset(arrayRow_data, 0, sizeof(arrayRow_data));

        capture_frame_free(imageFrame);
    }
    syslog(LOG_INFO, "ERROR:CAN NOT SEND IMAGE");
    capture_close_stream(imageStream);
    close(serverSocket);
    return 0;
}

//main function

//creating a socket
int main(void)
{
    //char server_message[256]= "Congrats, you have reached the server";
    int server_socket;
    int client_socket;
    int *new_socket;
    int conn;
    struct sockaddr_in server, client;

    server_socket = socket(AF_INET, SOCK_STREAM, 0);

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(1025);

    //bind the socket to the specified IP and port
    bind(server_socket, (struct sockaddr *)&server, sizeof(server));
    conn = sizeof(struct sockaddr_in);
    listen(server_socket, 5);

    //accept the connection from the client and send the message

    while ((client_socket = accept(server_socket, (struct sockaddr *)&client, (socklen_t *)&conn)))
    {

        pthread_t client_thread;
        new_socket = malloc(sizeof *new_socket);
        new_socket = client_socket;

        //establishing a message thread and possible errors
        if (pthread_create(&client_thread, NULL, client_handler, (void *)new_socket) < 0)
        {
            syslog(LOG_INFO, "ERROR. MESSAGE THREAD NOT ESTABLISHED");
            return 1;
        }
    }

    if (client_socket < 0)
    {
        syslog(LOG_INFO, "Sorry, client socket declined");
        free(new_socket);
        return 1;
    }

    return 0;
}

这是更新后的服务器代码。它有很多评论,因为我们想跟踪我们现在所做的事情。还是一样的问题:

#define _GNU_SOURCE -D

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <syslog.h>
#include <capture.h>
#include <sys/sendfile.h>
#include <pthread.h>
//define where the network camera is located
#define PORT_NUMBER 443
#define SERVER_ADDRESS "localhost"

//store recieved messages from client
//char cli_message;


//This is a buffer to store a welcome message to client in.
char buffer[1024];

char *message; //declared like this instead.


void * client_handler(void *server_socket) //This probably had the wrong input variable.

{
    //int serverSocket = (int) (intptr_t)server_socket; 
    int new_socket = (int)(intptr_t) (server_socket);   // this is a pointer to the server socket.
    //char *message, cli_message[2000];


    //HERE: get the media_stream BEFORE trying to fetch message
    media_stream *imageStream;
    media_frame *imageFrame;

    //ADDED: storing the image data.
    char *imageData;
    //ADDED: storing the size of the image data array.
    size_t imgSize;

    //MOVED and changed from server_socket
    recv(new_socket, message, 2000, 0); // receive information from client regarding resolution



    //MOVED. NOW we get the available resolutions.
    message = capture_get_resolutions_list(0);     //list of available image resolutions;

    //ADDED: Fetching the length of message in an int to make CERTAIN it's right and using a different method later in write to send it.
    int first_message_size = strlen(message);

    
    //write(serverSocket, message, strlen(message)); 
    write(new_socket, message, first_message_size); //send to client the list of resolutions
    write(new_socket, "\n", strlen("\n"));       //breaking line so the client can see the list


    memset(message, 0, strlen(message));           //resetting the message variable

    //Store the recieved resolution and FPS from client picked by user.
    recv(new_socket, message, 2000, 0);

    //opening the stream in order to capture image
    imageStream = capture_open_stream(IMAGE_JPEG, message);

    //send image to client with chosen resolution
    while (1) //condition always true, i.e. infinite loop
    {
        imageFrame = capture_get_frame(imageStream);
        imageData = capture_frame_data(imageFrame);

        imgSize = capture_frame_size(imageFrame);

        sprintf(message, "%zu\n", imgSize);          //converting the size to a char , and send to client
    
        write(new_socket, message, strlen(message)); //sending the size to the client
    
    //EDITED: sends image data to client, we also check if this write fails. We send imgSize, not sizeof(data).
    int sending = write(new_socket, imageData, imgSize);

    //Here we check that it's sending. If it isn't, the problem might be
    //that the CLIENT disconnected.
    if (sending < 0)
    {
        syslog(LOG_INFO, "ERROR! Failed to send. Client disconnected?");
    break;
    }

    //EDITED: Another reset of variables cause we DO NOT want to store this.
    memset(imageData, 0, sizeof(imageData));
    //memset(arrayRow_data, 0, sizeof(arrayRow_data));
    capture_frame_free(imageFrame);

        //unsigned char arrayRow_data[imgSize];
int arrayRow;


        for (arrayRow = 0; arrayRow < imgSize; arrayRow++)
        {

            imageData[imgSize] = imageData[arrayRow];

        }
    }//End of while

    
    syslog(LOG_INFO, "Exiting...");
    capture_close_stream(imageStream);
    close(new_socket);
    //ADDED
    pthread_exit(NULL);
    return 0;
}

    int start(void)
    {
        //(might solve our log issues)
        openlog ("server", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
        //message onto server log
        syslog(LOG_INFO, "Server running...");


        //char server_message[256]= "Congrats, you have reached the server";
        int server_socket;
        int new_socket;

        //int *new_socket;
        //int conn; //wat is dis?
        //struct sockaddr_in server, client;
        struct sockaddr_in server;
        struct sockaddr_storage storage; //This is new. Testing.
        socklen_t addressLength;

        server_socket = socket(PF_INET, SOCK_STREAM, 0); //Changed to PF
        server.sin_family = AF_INET;
        server.sin_port = htons(443);
        server.sin_addr.s_addr = htonl(INADDR_ANY);//we added htons & htonl

        //Deal with eventual padding field
        memset(server.sin_zero, '[=11=]', sizeof server.sin_zero);

        //bind the socket to the specified IP and port
        bind(server_socket, (struct sockaddr *) &server, sizeof(server));
        //conn = sizeof(struct sockaddr_in); ----> wat is?

        //Gave the listener a few more helpers. Longer time and max 40 con
        //requests.
        if(listen(server_socket, 50)==0)
        {
        syslog(LOG_INFO, "Listening\n");
        }
        else
        {
        syslog(LOG_INFO, "Not listening, lalalala.\n");
        }

        pthread_t client_thread[60]; //Move to outside of loop and given size.
        int i = 0; //used in the if-statement in the below while-loop.
        int end = 1; //used to end the while-loop.
        //accept the connection from the client and send the message
        while(end)
        {
        addressLength = sizeof storage;
           //new_socket = malloc(sizeof *new_socket);
        //new_socket = accept(server_socket, (struct sockaddr *) &client, (socklen_t *)&conn);
        *new_socket = accept(server_socket, (struct sockaddr *) &storage, &addressLength); //New addition

        //establishing a message thread and possible errors
        //if(pthread_create(&client_thread, NULL, client_handler, (void *)((intptr_t) new_socket))< 0)

        //Trying this if-statement instead..
        if(pthread_create(&client_thread[i], NULL,client_handler,(void *)((intptr_t) new_socket)) !=  0)

        {
            syslog(LOG_INFO, "ERROR. MESSAGE THREAD NOT ESTABLISHED!");
        }
        i++;

        if( i > 50)
        {
            end = 0;
        }
    }
    return 0;
}

//结束

这个

  new_socket = client_socket;

应该在编译期间发出警告。不要忽略编译器警告!

应该是:

  *new_socket = client_socket;

除此之外,对系统函数的许多重要调用都缺乏错误检查(recv()write())。

错误检查是免费调试的(对于投入生产的代码是强制性的)。

给定

pthread_create(&client_thread, NULL, client_handler, (void *)new_socket)

您将 new_socket 作为 void * 通过 而不是地址传递。

所以这是错误的:

int serverSocket = *(int *)server_socket;

由于您路过 you should write

pthread_create(&client_thread, NULL, client_handler, (void *)((intptr_t) new_socket) )

发送值和检索值
int serverSocket = (int)(intptr_t)server_socket;

这是总是错误:

void *client_handler(int server_socket)

pthread_create() 将参数作为 void * 传递。试图将其传递给接受 int 参数的函数在 void *int 大小不同的平台上根本行不通。在所有情况下都可能是未定义的行为,但我没有时间查找它。所以需要

void *client_handler(void *server_socket)

事实证明,这是因为使用的摄像头没有正确配置远程访问(不在我的控制之下)!

我仍然感谢所有给出的提示和指示。但是为了以后大家遇到同样的问题,感觉无法解决,这里有几点提示:

  1. 检查对相机端口的访问!这可以使用例如 Postman 来完成(保持在端口 1024 以上或尝试 80 或 8080)。
  2. 在开始处理更复杂的项目之前,运行 一个简单的 Hello World 解决方案可确保设置从一开始就正常运行。