3

可能重复:
从 C/C++ 中的 TCP 套接字读取的正确方法是什么?

我正在尝试开发一个 TCP 客户端/服务器。我的问题是,当我尝试从客户端发送数据时,我会一次性发送。

但是当我尝试接收具有特定结构的数据时出现了我的问题,我的意思是,前 8 个字节设置一个日期,接下来的 10 个字节设置一个名称,未定义的字节数设置一个文本(此文本以 /r/n 结尾/r/n)

客户端发送如下:

char date[8];
char name[10];
char msg[4096];

strcpy(msg,"12/10/12"); //8 bytes
strcat(msg,"Kevin Fire"); //10 bytes
strcat(msg,"abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde\r\n\r\n");

nbytes_sent = send(sock,(char *)msg,sizeof(msg),0);
printf("Bytes_sent: %s -> %i\n",msg,nbytes_sent);

服务器尝试解析来自套接字的数据,如下所示:

char date[8];
char name[10];
char * text;
char buf[1024];

int i=0;
for(i=0; i < 8; i++)
    date[i] = '\0';
for(i=0; i < 10; i++)
    name[i] = '\0';

nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
if(nbytes_read > 0){
    printf("Date: %s (%i)\n",date,nbytes_read);
    //cout.flush();
    nbytes_read=recv(sclient,(char *)name,sizeof(name),0);
    if(nbytes_read > 0){
        printf("Name: %s (%i)\n",name,nbytes_read);
        //cout.flush();
        nbytes_read=recv(sclient,(char *)buf,sizeof(buf),0);
        strcpy(text,buf);
        while(nbytes_read > 0){
            nbytes_read=recv(sclient(char*)buf,sizeof(buf),0);
            strcat(text,buf);
        }
    }
}

printf("Date: %s. Name: %s. Text: %s\n",date,name,text);
4

3 回答 3

6

这是一个简单的“接收所有”功能:

int recv_all(int sockfd, void *buf, size_t len, int flags)
{
    size_t toread = len;
    char  *bufptr = (char*) buf;

    while (toread > 0)
    {
        ssize_t rsz = recv(sockfd, bufptr, toread, flags);
        if (rsz <= 0)
            return rsz;  /* Error or other end closed cnnection */

        toread -= rsz;  /* Read less next time */
        bufptr += rsz;  /* Next buffer position to read into */
    }

    return len;
}
于 2012-10-02T18:35:54.647 回答
1

添加到@hmjd 的查找:

在 var decls 声明的是您的文本指针...

char * text;

然后后来...

strcpy(text,buf);
while(nbytes_read > 0){
   nbytes_read=recv(sclient(char*)buf,sizeof(buf),0);
   strcat(text,buf);
}

也许尝试将“文本”指针设置为随机堆栈值旁边的东西也会有所帮助。

继续弹幕,尽管以下不一定会爆炸,但您的date变量为:

char date[8];

在客户端和服务器端根本不使用客户端变量。但是,服务器变量是:

nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
if(nbytes_read > 0){

问题是,您发送的日期实际上已经是 8 个字符宽:“12/10/12”。因此,即使您在字符串末尾确定了一个空终止符,无论如何都应该这样做(良好做法):

date[ sizeof(date)/sizeof(date[0])-1 ] = 0;

您将截断日期的最后一个字符。

这还有其他问题;我们只指出了一些。考虑使用数组中的每个数据值发送长度前缀,并使用检查或范围来确保您获得预期的结果。

最后,在调试器的业务端花一些时间可能会做得很好,尤其是在服务器端。

于 2012-10-02T14:19:22.137 回答
1

一个(重复的)错误是:

nbytes_read=recv(sclient,(char *)date,sizeof(date),0);

recv()不为空终止。这意味着如果读取字节,则date不会有空终止符。sizeof(date)当非空终止字符串作为参数传递给printf()with"%s"格式说明符时,这是一个问题。如果字符串是非空终止的,您可能会看到在实际字符串数据之后出现垃圾字符。您需要读取比目标缓冲区少一并且空终止或使用"%*.s"不需要空终止的格式说明符:

printf("%.*s", n, s); /* Prints first 'n' bytes from 's'. */

请注意,您可以将 a 初始化char[]为所有空值,而不是使用 a for

char date[8] = "";

或者你可以使用memset().

于 2012-10-02T14:12:15.113 回答