我正在尝试通过发送 2 种类型的消息创建一个与服务器通信的客户端:
- 与服务器通信以关闭连接的单词
QUIT
。 - 具有以下语法的操作:运算符first_operand second_operand。例如:
+ 3 3
、- 5 6
等(操作数必须是正整数,并且必须只有 2 个操作数(。
如果服务器收到操作,它将执行该操作并将结果返回给客户端。问题是我发送的第一个操作返回正确的结果,而接下来的操作随机工作(有时它们返回正确的结果,有时函数strtok()
没有获得第二个操作数并返回NULL
......
这是客户端的代码,它处理用户在提示中编写的消息,并扫描消息以检查操作是否使用正确的语法编写(警告:代码以极其不专业和不干净的方式编写(。
产生问题的代码部分位于while(1)
内。
#define MAXLENGTH 256
int main (int argc, char *argv[]) {
int simpleSocket = 0;
int simplePort = 0;
int returnStatus = 0;
char first[10], second[10];
char* operator;
char buffer[MAXLENGTH] = "";
char message[50];
char terminationCommand[] = "QUITn";
char space[2] = " ";
struct sockaddr_in simpleServer;
if (3 != argc) {
fprintf(stderr, "Usage: %s <server> <port>n", argv[0]);
exit(1);
}
/* create a streaming socket */
simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (simpleSocket == -1) {
fprintf(stderr, "Could not create a socket!n");
exit(1);
} else {
fprintf(stderr, "Socket created!n");
}
/* retrieve the port number for connecting */
simplePort = atoi(argv[2]);
/* setup the address structure */
/* use the IP address sent as an argument for the server address */
//bzero(&simpleServer, sizeof(simpleServer));
memset(&simpleServer, ' ', sizeof(simpleServer));
simpleServer.sin_family = AF_INET;
//inet_addr(argv[2], &simpleServer.sin_addr.s_addr);
simpleServer.sin_addr.s_addr=inet_addr(argv[1]);
simpleServer.sin_port = htons(simplePort);
/* connect to the address and port with our socket */
returnStatus = connect(simpleSocket, (struct sockaddr *)&simpleServer, sizeof(simpleServer));
if (returnStatus == 0) {
fprintf(stderr, "Connect successful!nn");
} else {
fprintf(stderr, "Could not connect to address!n");
close(simpleSocket);
exit(1);
}
/* get the message from the server */
returnStatus = read(simpleSocket, buffer, sizeof(buffer));
if (returnStatus > 0) {
printf("%sn", &buffer[3]);
} else {
fprintf(stderr, "Return Status = %d n", returnStatus);
}
memset(&buffer, ' ', sizeof(buffer));
printf("You can execute 2 commands:n");
printf("1. Operations ( +, -, *, /, % ) with the following syntax: operator + first operand + second operand.n");
printf("Example: + 5 2 n");
printf("2. Termination of the connection with the following syntax: QUIT + press Enter.n");
while(1) {
printf("nEnter a command:n");
fgets(message, 1000, stdin);
// the if with the termination command works fine
if (strcmp(message, terminationCommand) == 0) {
if (send(simpleSocket, message, strlen(message), 0) < 0) {
printf("Send failed.");
return 1;
}
returnStatus = read(simpleSocket, buffer, sizeof(buffer));
if (returnStatus > 0) {
printf("%sn", &buffer[4]);
} else {
fprintf(stderr, "Return Status = %d n", returnStatus);
}
close(simpleSocket);
exit(1);
}
operator = strtok(message, space);
if (strcmp(operator, "+") == 0 || strcmp(operator, "-") == 0 || strcmp(operator, "/") == 0 || strcmp(operator, "%") == 0 || strcmp(operator, "*") == 0) {
char *first_operand = strtok(NULL, space);
if (first_operand != NULL) {
if (strcmp(first_operand, "ANS") == 0)
strcpy(first, "ANS");
else
strcpy(first, first_operand);
printf("%sn", operator);
printf("%sn", first);
char *second_operand = strtok(NULL, space);
printf("%sn", second_operand);
if (second_operand != NULL && strtok(NULL, space) == NULL && (atoi(first) > 0 || strcmp(first, "ANS") == 0)) {
if (strcmp(second_operand, "ANSn") == 0)
strcpy(second, "ANS");
else {
strcpy(second, second_operand);
}
if (atoi(second) > 0 || strcmp(second, "ANS") == 0) {
printf("OKn");
char operation[] = "";
strcat(operation, operator);
strcat(operation, " ");
strcat(operation, first);
strcat(operation, " ");
strcat(operation, second);
if (send(simpleSocket, operation, strlen(operation), 0) < 0) {
printf("Send failed.");
return 1;
}
returnStatus = read(simpleSocket, buffer, sizeof(buffer));
if (returnStatus > 0) {
printf("%sn", buffer);
} else {
fprintf(stderr, "Return Status = %d n", returnStatus);
}
}
}
}
}
// after everything I reset the buffers I use to memorize the message and the elements of the message
memset(&buffer, ' ', sizeof(buffer));
memset(&first, ' ', sizeof(first));
memset(&second, ' ', sizeof(second));
memset(&message, ' ', sizeof(message));
memset(operator, ' ', sizeof(operator));
}
}
有人能告诉我为什么第二strtok()
90%的时间表现得很奇怪吗?我做错了什么?
程序中存在多个问题:
您发送换行终止的消息,并假设另一端read
将准确返回另一方发送的字节数,这对于 TCP/IP 通信来说是一个不正确的假设,只保证接收的字节顺序,但消息可以在途中拆分并以不同于发送顺序的块接收。相反,您应该将套接字读入缓冲区,并且仅在收到换行符时才处理它。
在您的情况下,还有另一个更紧迫的问题:您read
数据的缓冲区不是 null 终止的,因此您不应该将其传递给标准 C 函数,例如strtok()
。