0

我编写的两个程序(服务器和客户端)遇到了一些问题。为了保持简单和按时间顺序,我首先编写了服务器并使用 telnet 和 netcat 对其进行了测试,一切正常(除了 read() / recv() 的返回值不同,因为它看起来像普通的 telnet 程序在要发送的字符串末尾添加一个额外的字符,但无论如何......)。

现在我也编写了客户端程序,但我没有得到其他两个客户端正确接收的所有数据,特别是我从 MySQL 查询中获得的 row[i] 字符串。当我在每个 send() 函数之后引入 usleet() 调用并且正确接收所有数据时,情况会发生变化。

现在我正在考虑一个不兼容的缓冲区大小问题(?),但是在玩了一段时间并检查了尺寸之后,我什么也找不到。

您将在下面找到代码,如果您有任何建议,请随时告诉我。

肿瘤坏死因子

/* 客户代码 */

#define BUFSIZE 1000
...
void *send_handler(void *);
...
int main(int argc, char *argv[]) {
    char buf[BUFSIZE];
    ...
    socket stuff...
    ...
    connect
    ...
    /* receive string from server - working */
    bzero(buf, BUFSIZE);
    n = read(sockfd, buf, BUFSIZE);
    if (n < 0) 
        error("ERROR reading from socket");
    buf[n] = '\0';
    printf("%s", buf);
    ...
    /* send username to server - working */
    bzero(buf, BUFSIZE);
    fgets(buf, BUFSIZE, stdin);
    n = write(sockfd, buf, strlen(buf));
    if (n < 0) 
        error("ERROR writing to socket");
    ...
    /* start receiving handler */
    if( pthread_create( &thread_id , NULL , send_handler , (void*) &sockfd) < 0) {
    perror("could not create thread");
        return 1;
    }

    /* main thread for reading data */
    while(1) {
        bzero(buf, BUFSIZE);
        n = read(sockfd, buf, BUFSIZE);
        if (n < 0) 
    error("ERROR reading from socket");
    buf[n] = '\0';
    printf("%s", buf);
    }

    close(sockfd);
    return 0;
}

void *send_handler(void *socket_desc) {
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    char buf[BUFSIZE];
    int n;

    while (1) {
        bzero(buf, BUFSIZE);
        fgets(buf, BUFSIZE, stdin);
        n = write(sock, buf, strlen(buf));
        if (n < 0) 
            error("ERROR writing to socket");
    }
}

/* 服务器代码 */

void *connection_handler(void *);

int main(int argc , char *argv[]) {
    ...
    /* socket variables */
    ...
    pthread_t thread_id;
    ...
    socket stuff...
    ...
    while((client_sock = accept(socket_desc, (struct sockaddr *)&client_addr, (socklen_t*)&client_len))) {
        if( pthread_create( &thread_id , NULL , connection_handler , (void*) &client_sock) < 0) {
        perror("could not create thread");
            return 1;
    }
    }
    return 0;
}

void *connection_handler(void *socket_desc) {
//Get the socket descriptor
int sock = *(int*)socket_desc;
    ...
    /* mysql variables */
char cmd[1000];
...
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL *con;
...
/* connection variables */
int read_size, i;
char *message;
char client_message[2000];
char buffer[1000];
    ...
    //clear the buffers
memset(client_message, '\0', 2000);
    ...
    snprintf(cmd, 999, "SELECT field1, field2, field3, field4 FROM files WHERE key='%s' ORDER BY id DESC", var);
if (mysql_query(con, cmd)) {
    error checks...
}
result = mysql_store_result(con);
if (result == NULL) {
    error checks...
}
else {
    num_rows = mysql_num_rows(result);
}
if (num_rows == 0) {
    message = "Nothing found\n";
    send(sock , message , strlen(message), 0);  
}
    else {
    num_fields = mysql_num_fields(result);
    num_rows = mysql_num_rows(result);
        snprintf(buffer, 999, "Number of rows: %d\n", num_rows);
    send(sock , buffer , sizeof(buffer), 0);
    //usleep(10000); // commented, but necessary to work properly...
        memset(buffer, '\0', sizeof(buffer));

        while ((row = mysql_fetch_row(result))) { 
    for(i = 0; i < num_fields; i++) {
        snprintf(buffer, 999, "%s\t", row[i] ? row[i] : "NULL");
        send(sock , buffer , sizeof(buffer), 0);
        //usleep(10000);
        memset(buffer, '\0', sizeof(buffer));
        }
        message = "\n";
        send(sock , message , strlen(message), 0);
        //usleep(10000);
    }
    message = "\n";
    send(sock , message , strlen(message), 0);
        //usleep(10000);
    mysql_free_result(result);
}
...
}

编辑:我改变了 printf("%s", buf);

with printf("读取的字节数:%d\n", n); 在客户端代码中,我获得了以下输出:

带有注释的 usleep():

Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 36
Bytes read: 1000
Bytes read: 31
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 2
(17 lines)

使用 usleep(0) 减慢发送流(获得正确的输出):

Bytes read: 1000
Bytes read: 33
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1
Bytes read: 1
Bytes read: 1000
Bytes read: 31
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1000
Bytes read: 1
Bytes read: 1
(21 lines)

有什么提示吗?

已解决:只需更换

sizeof(buffer);

strlen(buffer);

在服务器部分,即使没有 usleep(),一切正常,输出是正确/完整的。

不管怎么说,还是要谢谢你。

4

2 回答 2

4

您不能假设单次阅读会阅读整条消息。TCP 中没有消息,只有字节,任何给定的读取都可能返回少至一个字节,或者同时在对等方多次写入的结果。你必须循环和解析。

于 2013-07-06T00:55:52.023 回答
1

您的代码中有竞争条件,您将指向局部变量的指针传递给线程函数。由于文件描述符(int)不大于 void 指针(我很确定这是有保证的,但仍然添加一个断言),您还可以将描述符转换为指针,而不是传递本地文件描述符的地址:

int s = accept(...);
if(int e = pthread_create(.., &connection_handler, (void*)s, ..))
    error(..);

顺便说一句: pthread_create 在成功时返回零,否则返回错误代码,这不是负数。但是您的代码在那时失败的可能性很小。

于 2013-07-06T00:29:56.097 回答