运行服务器之后,我运行了两个客户端实例。现在我第一次运行客户端时,接收到的数据被保存到数组[0]中,但是当我运行第二个客户端时,数组[0]的值会被新值意外地覆盖。新数据应保存在数组[1]中,而不是覆盖。我犯了什么错误?
char * Array [100]; int ArrayCount = 0;是全局变量。
void *server()
{
int listenfd = 0;
connfd = 0;
struct sockaddr_in serv_addr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(port));
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
{
perror("bind");
exit(1);
}
listen(listenfd, 10);
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
printf("data in Array[0] before recv : %s\n",Array[0]);
int ns;
char revdData[2000];
bzero(revdData,2000);
ns = recv(connfd,revdData,2000,0);
close(connfd);
printf("data in Array[0] after recv : %s\n",Array[0]);
Array[ArrayCount] = revdData;
ArrayCount = ArrayCount+1;
}
}
客户端代码
void *client()
{
int soctype = SOCK_STREAM;
struct hostent *hp, *gethostbyname();
struct sockaddr_in servR;
struct servent *seR;
int tempSocket;
char *host = "localhost";
if ((tempSocket = socket(AF_INET, soctype, 0)) < 0)
{
perror("socket");
exit(1);
}
if ((hp = gethostbyname(host)) == NULL)
{
exit(1);
}
servR.sin_family = AF_INET;
memcpy(&servR.sin_addr, hp->h_addr, hp->h_length);
if (isdigit(*port))
{
servR.sin_port = htons(atoi(port));
}
else
{
if ((seR = getservbyname(port, (char *)NULL)) < (struct servent *) 0)
{
perror(port);
exit(1);
}
servR.sin_port = seR->s_port;
}
if (connect(tempSocket, (struct sockaddr *) &servR, sizeof(servR)) < 0)
{
perror("connect");
exit(1);
}
char input[100];
fgets(input,100,stdin);
int n;
n=send(tempSocket,input,100,0);
if (n < 0)
{
error("Send");
}
}
输出如下:
data in Array[0] before recv : (null)
data in Array[0] after recv : (null)
data in Array[0] before recv : 1st Instance
data in Array[0] after recv : 2nd Instance
理想情况下,recv后的数据应为“1st instance”,因为我正在打印数组[0]。
答案 0 :(得分:4)
服务器代码中的这个赋值没有达到你想要的效果:
Array[ArrayCount] = revdData;
这是无效代码,因为revdData
是一个本地数组,其范围分隔为server()
。赋值不复制数组,它将指针复制到第一个元素。因此,当您从server()
返回时,Array
包含指向无效位置的指针 - 本地revdData
数组的内存无效。接下来发生的事情是未知的通常,由于您将再次调用server()
,因此很可能会为新的revdData
数组重用相同的内存空间,因此最终会覆盖您不想要的内容。 / p>
要解决此问题,您必须在Array[ArrayCount]
中分配内存,然后使用strncpy
,或使用strndup
。
以下是您可以使用strncpy
:
Array[ArrayCount] = malloc(ns);
strncpy(Array[ArrayCount], revdData, (size_t) ns);
此外,您可以将ns
从int
更改为ssize_t
,这是recv
的返回类型。
如果要使用strndup
,则不需要显式使用malloc
,但是,如果您的数据包含空字节,则不会复制超出该点,如果它没有' t,它会在重复的字符串中添加一个空字节,这可能不是你想要的。
请注意,此方法引入了内存管理问题;在某些时候,你必须释放为Array
中的每个位置分配的内存。您负责执行此操作,但在小程序中,您通常可以依赖于在程序终止时操作系统释放所有已分配的内存的事实。
答案 1 :(得分:1)
您只是将指针revdData
复制到Array[i]
。因此,您的所有Array
元素都只指向revdData
。
您应该为Array
元素分配一些内存,并将revdData
的值复制到Array[ArrayCount]
。
// Just after you recv
Array[ArrayCount] = malloc(sizeof(char) * ns);
strncpy(Array[ArrayCount], revdData, (size_t)ns);
ArrayCount++;
// Free allocated memory before you exit
for(i = 0; i < ArrayCount; i++) {
free(Array[ArrayCount]);
Array[ArrayCount] = 0;
}
请参阅一些教程以获得更好的客户端/服务器设计。