#include <WinSock2.h>
#include <cstdlib>
#include <cstdio>
#include <inaddr.h>
int calculate(int aopNum, int aopVal[], char aop) {
int result = aopVal[0], i;
switch(aop)
{
case '+':
for(i = 1; i < aopNum; i++) result += aopVal[i];
break;
case '-':
for(i = 1; i < aopNum; i++) result -= aopVal[i];
break;
case '*':
for(i = 1; i < aopNum; i++) result *= aopVal[i];
break;
}
return result;
}
int main() {
WSADATA wsadata;
const int bufSize = 1000;
const int opSize = 4;
int port = 5099;
// int result;
if(WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
printf("Failed to init\n");
return -1;
} else {
printf("Inited \n");
}
SOCKADDR_IN addrServ;
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(port);
SOCKET sockServ = socket(AF_INET, SOCK_STREAM, 0);
if(bind(sockServ, (SOCKADDR *)&addrServ, sizeof(SOCKADDR)) == SOCKET_ERROR) {
printf("Fail to bind \n");
} else {
printf("Binded \n");
}
if(listen(sockServ, 10) == SOCKET_ERROR) {
printf("Fail to listen \n");
} else {
printf("Listening \n");
}
fflush(stdout);
SOCKADDR_IN addrClnt;
int len = sizeof(addrClnt);
// SOCKET sockClnt = socket(AF_INET, SOCK_STREAM, 0);
char bufRecv[bufSize];
int opnum;
int recvLen = 0;
// SOCKET sockClnt;
while(1) {
SOCKET sockClnt = accept(sockServ, (SOCKADDR *)&addrClnt, &len);
if(sockClnt == SOCKET_ERROR) {
printf("Fail to accept \n");
return -1;
} else {
printf("Accepted \n");
}
fflush(stdout);
recv(sockClnt, (char *)&opnum, 1, 0);
//int opnum = (int)(copnum - '0');
printf("%d\n", opnum);
fflush(stdout);
while((opSize * opnum + 1) > recvLen) {
int len1 = recv(sockClnt, &bufRecv[recvLen], bufSize - 1, 0);
recvLen += len1;
}
printf("%c\n", bufRecv[recvLen - 1]);
fflush(stdout);
//testbegin:
int *p = (int *)bufRecv;
for(int j = 0; j < opnum; j++) {
printf("%d ", p[j]);
fflush(stdout);
}
int result = calculate(opnum, (int *)bufRecv, bufRecv[recvLen - 1]);
printf("%d\n", result);
fflush(stdout);
send(sockClnt, (char *)&result, sizeof(result), 0);
closesocket(sockClnt);
}
//closesocket(sockClnt);
WSACleanup();
return 0;
}
client.cpp:
#include <WinSock2.h>
#include <cstdlib>
#include <cstdio>
#include <inaddr.h>
int main() {
WSADATA wsadata;
const int bufSize = 1000;
const int opSize = 4;
int opNum;
int port = 5099;
int result;
// char cresult;
if(WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
printf("Fail to init \n");
return -1;
}
SOCKADDR_IN servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
SOCKET sockClnt = socket(AF_INET, SOCK_STREAM, 0);
if(connect(sockClnt, (SOCKADDR *)&servAddr, sizeof(servAddr)) != 0) {
printf("Fail to connect \n");
} else {
printf("Connected \n");
}
fflush(stdout);
char bufSent[bufSize];
printf("Input the num of numbers: \n");
fflush(stdout);
scanf("%d", &opNum);
bufSent[0] = (char)opNum;
printf("Input the numbers \n");
fflush(stdout);
for(int i = 0; i < opNum; i++) {
scanf("%d", (int *)&bufSent[1 + i * opSize]);
}
fgetc(stdin);
printf("Input the operator: \n");
fflush(stdout);
scanf("%c", &bufSent[1 + opNum * opSize]);
send(sockClnt, bufSent, opNum * opSize + 2, 0);
recv(sockClnt, (char *)&result, sizeof(result), 0);
printf("The result is %d", result);
fflush(stdout);
// delay(5);
closesocket(sockClnt);
WSACleanup();
return 0;
}
问题是运行服务器后,我启动了一个客户端并输入:
3
2
4
6
*
它可以正确返回2 * 4 * 6 = 48
。但是,当我启动新客户端而不停止服务器时,我输入:
3
2
4
6
+
,它仍然返回48(即使我输入了2 + 4 + 6 = 12
,它也返回48(而不是3 1 2 3
)。我尝试了很多,但仍然无法解决。所以我现在在这里寻求帮助。
答案 0 :(得分:1)
应将recvLen
变量移至while(1)循环中:
while (1) {
int recvLen = 0;
它包含来自先前连接的值,并且值/运算符的位置不清楚(没有完全检查它)。经过多次连接后,如果不进行更改,代码也将崩溃(缓冲区指针始终移动,缓冲区是堆栈上的静态数组)
行
recv(sockClnt, (char *)&opnum, 1, 0);
是危险的..它将单个字节读取为整数。该int的3个字节不受影响,并且可能包含未初始化的内存。最好是传输一个整数(4个字节),或者至少将变量设置为0:
int opnum = 0;