我在编写的两个程序,服务器和客户端时遇到了一些问题。为了保持简单和按时间顺序,我首先编写服务器并使用telnet和netcat进行测试,一切正常(除了read()/ recv()的返回值之外,因为它看起来像普通的telnet程序在要发送的字符串末尾添加一个额外的字符,但无论如何......)。
现在我也编写了客户端程序,但是我没有得到其他两个客户端正确接收的所有数据,特别是我从MySQL查询得到的row [i]字符串。当我在每个send()函数之后引入usleet()调用并且正确接收所有数据时,事情会发生变化。
现在我正在考虑一个不兼容的缓冲区大小问题(?),但是在玩了一段时间并检查尺寸后,我无法找到任何东西。
您将在下面找到以下代码,如果您有任何建议,请随时告诉我。
TNX
/ *客户代码* /
#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);
与 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(),一切正常,输出正确/完整。
非常感谢。
答案 0 :(得分:4)
您不能假设单个读取读取整个消息。 TCP中没有消息,只有字节,任何给定的读取都可以返回少至一个字节,或者同时在对等体上多次写入的结果。你必须循环和解析。
答案 1 :(得分:1)
您的代码中存在竞争条件,您将指向本地变量的指针传递给线程函数。由于filedescriptor(int)不大于void指针(我确信这是有保证的,但是仍然添加一个断言),你也可以将描述符 value 转换为指针而不是传递本地文件描述符的地址:
int s = accept(...);
if(int e = pthread_create(.., &connection_handler, (void*)s, ..))
error(..);
BTW:pthread_create在成功时返回零,否则返回错误代码,这不是负数。但是你的代码在那时不太可能失败。