首页 > 解决方案 > read() 不读取套接字缓冲区上的剩余字节

问题描述

我创建了两个程序,一个客户端和一个服务器。它们通过发送char固定大小为 115 字节的数组的套接字进行通信。

我要传输的数据存储在以下位置struct

typedef struct {
    char origin[14];
    char type;
    char data[100];
} socket_data;

但是为了发送序列化的数据,我想在一个连接所有字段的字符串中发送该信息,struct所以我发送了一个 115 字节的字符串。如果这些字段中的任何一个未达到其最大大小,我将手动填充额外的数组位置\0

我创建了两个在客户端和服务器中实现的函数,它们通过套接字发送数据或从套接字接收数据。

这两个函数如下:

void socket_send(int socket, char *origin, char type, char *data) {

    char info[115]; //data to be sent
    socket_data aux;
    strcpy(aux.origin, origin);
    aux.type = type;
    strcpy(aux.data, data);
    
    //Filling up the remaining positions of origin and data variables
    for (int i = (int) strlen(aux.origin); i<14; i++) aux.origin[i] = '\0';
    for (int i = (int) strlen(aux.data); i<100; i++) aux.data[i] = '\0';
    
    //Building up the 115 byte string I want to send via socket
    for (int i=0; i<14; i++) info[i] = aux.origin[i];
    info[14] = type;
    for (int i=0; i<100; i++) info[i+15] = aux.data[i];

    ssize_t total_bytes = 115;
    ssize_t bytes_written = 0;

    //Here I send all the bytes through the socket
    do {
        bytes_written = write(socket, info + (115 - total_bytes), total_bytes);
        total_bytes -= bytes_written;
    } while (total_bytes > 0);
}

socket_data socket_rcv(int socket) {
    socket_data info;
    char sequence[115];
    ssize_t total_bytes = 115;
    ssize_t bytes_read = 0;

    //Here I receive all the bytes from the socket (till I fill up the 115 byte string called sequence)
    do {
        bytes_read = read(socket, sequence + (115 - total_bytes), total_bytes);
        total_bytes -= bytes_read;
    } while (total_bytes > 0);
    
    //Then I return a stuct
    for (int i=0; i<14; i++) info.origin[i] = sequence[i];
    info.type = sequence[14];
    for (int i=0; i<100; i++) info.data[i] = sequence[i+15];

    return info;
}

如您所见,我循环read()write()确保发送所有字节,因为我知道有时这些函数读取或写入的字节数少于要求的字节数。

问题是,在测试程序的功能时,我发现在读取的字节数较少(它循环)的情况下,程序会阻塞(可能等待write()来自服务器端的另一个字节)而不是读取剩余的字节套接字缓冲区(因为发送了所有 115 个字节而只接收了 111 个字节,所以套接字缓冲区中应该还有 4 个字节)。有时,程序不是阻塞等待可能write()的,而是在它不应该终止时终止......

我在这里找不到问题,我会很感激一些帮助

编辑

我创建了这个函数来设置套接字......

服务器:

int socketConfig (connection_info cinfo) {

    int socketfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (socketfd < 0) {
        write(1, "Socket error\n", strlen("Socket error\n"));
        return -1;
    }

    struct sockaddr_in s_addr;
    memset (&s_addr, 0, sizeof (s_addr));
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(cinfo.port);
    s_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind (socketfd, (void *) &s_addr, sizeof (s_addr)) < 0) {
        write(1, "Bind error\n", strlen("Bind error\n"));
        return -1;
    }

    listen(socketfd, 3);

    return socketfd;
}

int receiveClient(int serverfd) {
    struct sockaddr_in client;
    socklen_t len = sizeof(client);

    return accept(serverfd, (void *) &client, &len);
}

客户:

int connect_to_server(Config config) {
    struct sockaddr_in client;
    int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    write(1, "Connecting Jack...\n", strlen("Connecting Jack...\n"));

    if (sockfd < 0) {
        write(1, "Error creating the socket\n", strlen("Error creating the socket\n"));
        return -1;
    }

    memset(&client, 0, sizeof(client));

    client.sin_family = AF_INET;
    client.sin_port = htons(config.port_jack);

    if (inet_aton(config.ip_jack, &client.sin_addr) == 0) {
        write(1, "Invalid IP address\n", strlen("Invalid IP address\n"));
        return -1;
    }

    if (connect(sockfd, (void *) &client, sizeof(client)) < 0) {
        write(1, "Error connecting to Jack\n", strlen("Error connecting to Jack\n"));
        return -1;
    }

    return sockfd;
}

我可以保证连接正常

标签: csockets

解决方案


您没有检查失败的返回值write()read()失败。

尝试更多类似的东西:

int socket_send_all(int socket, const void *data, size_t size) {
    const char *pdata = (const char*) data;
    ssize_t bytes_written;
    while (size > 0) {
        bytes_written = write(socket, pdata, size);
        if (bytes_written < 0) return bytes_written;
        pdata += bytes_written;
        size -= bytes_written;
    }
    return 0;
}

int socket_rcv_all(int socket, void *data, size_t size) {
    char *pdata = (char*) data;
    ssize_t bytes_read;
    while (size > 0) {
        bytes_read = read(socket, pdata, size);
        if (bytes_read <= 0) return bytes_read;
        pdata += bytes_read;
        size -= bytes_read;
    }
    return 1;
}

int socket_send2(int socket, const socket_data *sd) {

    char bytes[115];
    memcpy(bytes, sd->origin, 14);
    bytes[14] = sd->type;
    memcpy(bytes+15, sd->data, 100);
    return socket_send_all(socket, bytes, 115);

    /* alternatively:

    int ret = socket_send_all(socket, sd->origin, 14);
    if (ret == 0) ret = socket_send_all(socket, &(sd->type), 1);
    if (ret == 0) ret = socket_send_all(socket, sd->data, 100);
    return ret;

    */
}

int socket_send(int socket, char *origin, char type, char *data) {

    socket_data aux;
    strncpy(aux.origin, origin, 14);
    aux.type = type;
    strncpy(aux.data, data, 100);

    return socket_send2(socket, &aux);
}

int socket_rcv2(int socket, socket_data *sd) {
    char bytes[115];
    int ret = socket_rcv_all(socket, bytes, 115);
    if (ret > 0) {
        memcpy(sd->origin, bytes, 14);
        sd->type = bytes[14];
        memcpy(sd->data, bytes+15, 100);
    }
    return ret;

    /* alternatively:

    int ret = socket_rcv_all(socket, sd->origin, 14);
    if (ret > 0) ret = socket_rcv_all(socket, &(sd->type), 1);
    if (ret > 0) ret = socket_rcv_all(socket, sd->data, 100);
    return ret;

    */
}

socket_data socket_rcv(int socket) {
    socket_data aux;
    int ret = socket_rcv2(socket, &aux);
    if (ret <= 0) {
        // error handling ...
    }
    return aux;
}

推荐阅读