【问题标题】:array value changing unexpectedly after recv()recv() 后数组值意外更改
【发布时间】:2014-02-21 17:18:05
【问题描述】:

在我运行服务器之后,我运行了两个客户端实例。现在我第一次运行客户端时,接收到的数据被保存到数组 [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 之后的数据应该是“第一个实例”,因为我正在打印数组 [0]。

【问题讨论】:

  • struct hostent *hp, *gethostbyname(); 不好。相反,#include 是相应的头文件。或者更好的是,将getservbyname()gethostbyname() 替换为较新的getaddrinfo()getnameinfo()

标签: c sockets recv


【解决方案1】:

服务器代码中的这个赋值不是你想要的:

Array[ArrayCount] = revdData;

这是无效的代码,因为revdData 是一个本地数组,其范围限定为server()。赋值不会复制数组,它会将指针复制到它的第一个元素。因此,当您从 server() 返回时,Array 包含一个指向无效位置的指针 - 本地 revdData 数组的内存无效。接下来会发生什么就不得而知了。通常,由于您将再次调用server(),因此很有可能相同的内存空间被重新用于新的revdData 数组,因此它最终会覆盖您不想要的内容。

要修复它,您必须在Array[ArrayCount] 中分配内存然后使用strncpy,或者使用strndup

您可以使用strncpy 执行以下操作:

Array[ArrayCount] = malloc(ns);
strncpy(Array[ArrayCount], revdData, (size_t) ns);

另外,您可以将nsint 更改为ssize_t,这是recv 的返回类型。

如果你想使用strndup,你不需要显式使用malloc,但是,如果你的数据包含空字节,它不会复制超过那个点,如果没有,它会在重复的字符串中添加一个空字节,这可能不是您想要的。

注意,这种方式引入了内存管理的问题;在某些时候,您必须释放分配给Array 中每个位置的内存。您有责任执行此操作,尽管在小型程序中您通常可以依赖这样一个事实,即在程序终止时操作系统会释放所有分配的内存。

【讨论】:

    【解决方案2】:

    您只是将指针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;
    }
    

    请参阅一些教程以获得更好的客户端/服务器设计。

    【讨论】:

    • 这行不通。你不能将sizeof(Array[ArrayCount]) 传递给strncpy,因为这将评估为char * 的大小——不是你想要的。 Array[ArrayCount] 不是一个数组,它是一个指针。你应该用ns替换它。
    • @FilipeGonçalves 谢谢 :-)
    猜你喜欢
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-05
    相关资源
    最近更新 更多