如何发送和接收数据套接字TCP (C/ c++)[副本]

时间:2022-10-17 07:35:48

Possible Duplicate:
What is the correct way of reading from a TCP socket in C/C++?

可能复制:在C/ c++中,从TCP套接字读取的正确方式是什么?

I'm trying to develop a TCP client/server. My problem is, when I try to send the data from cliente I do it in one sent.

我正在尝试开发一个TCP客户机/服务器。我的问题是,当我试图发送来自cliente的数据时,我在发送一个。

But my problem appears when I try to receive the data with a specific structure, I mean, the first 8 bytes set a date, the next 10 a name, and undefined number of bytes set a text (this text ends with /r/n/r/n)

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

The client sends as follows:

客户端发送如下:

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);

And the server try to parse the data from socket as follows:

服务器试图解析来自套接字的数据如下:

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);

3 个解决方案

#1


5  

Here's a simple "receive all" function:

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

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;
}

#2


1  

One (repeated) mistake is:

(重复)的错误是:

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

recv() does not null terminate. This means date will not have a null terminator if sizeof(date) bytes is read. This is a problem when a non-null terminated string is passed as an argument to printf() with "%s" format specifier. If the string is non-null terminated you may see garbage characters appearing after the actual string data. You need to read one less than the target buffer and null terminate or use the format specifier "%*.s" that does not require null termination:

recv()不会终止。这意味着如果读取了sizeof(日期)字节,日期将不会有一个空终止符。当使用“%s”格式说明符将非空终止字符串作为参数传递给printf()时,这是一个问题。如果字符串是非空的,则可以看到在实际字符串数据之后出现的垃圾字符。您需要读取小于目标缓冲区和空终止或使用格式说明符“%*”的值。s“不要求零终止:

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

Note you can initialise a char[] to all nulls instead of using a for:

注意,您可以将char[]初始化为所有的null,而不是使用for:

char date[8] = "";

or you can use memset().

或者您可以使用memset()。

#3


1  

Adding to @hmjd's find:

增加@hmjd找到:

declared at the var decls is your text pointer...

在var decls中声明是你的文本指针…

char * text;

then later...

后来……

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

Maybe try setting that 'text' pointer to something beside a random stack value will help as well.

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

Continuing the barrage, though the following will not necessarily blow up, your date variable as:

继续弹幕,尽管下面的不一定会爆炸,你的日期变量为:

char date[8];

on both client and server side The client variable isn't used at all. The server variable, however is:

在客户端和服务器端,客户端变量都没有使用。然而,服务器变量是:

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

Problem is, the date you sent is, in fact, 8 chars wide already: "12/10/12". Therefore, even if you firm-up a null terminator on the end of your string, which you should always do regardless (good practice):

问题是,你发送的日期实际上已经是8个字符了:“12/10/12”。因此,即使您的字符串末尾有一个空终止符,您也应该始终这样做(良好的实践):

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

you'll be truncating off the last char of your date.

你将会截断你约会对象的最后一个字符。

There are other things wrong with this; we've only pointed out a few. Think about sending length-prefixes with each of these data values in the array, with checks or range to ensure you get what you expected.

还有其他的问题;我们只指出了一些。考虑在数组中使用每个数据值发送长度前缀,通过检查或范围来确保得到您所期望的。

Finally, spending some time on the business-end of a debugger would probably do you very well, especially on the server side.

最后,花点时间在调试器的业务端可能会非常好,尤其是在服务器端。

#1


5  

Here's a simple "receive all" function:

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

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;
}

#2


1  

One (repeated) mistake is:

(重复)的错误是:

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

recv() does not null terminate. This means date will not have a null terminator if sizeof(date) bytes is read. This is a problem when a non-null terminated string is passed as an argument to printf() with "%s" format specifier. If the string is non-null terminated you may see garbage characters appearing after the actual string data. You need to read one less than the target buffer and null terminate or use the format specifier "%*.s" that does not require null termination:

recv()不会终止。这意味着如果读取了sizeof(日期)字节,日期将不会有一个空终止符。当使用“%s”格式说明符将非空终止字符串作为参数传递给printf()时,这是一个问题。如果字符串是非空的,则可以看到在实际字符串数据之后出现的垃圾字符。您需要读取小于目标缓冲区和空终止或使用格式说明符“%*”的值。s“不要求零终止:

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

Note you can initialise a char[] to all nulls instead of using a for:

注意,您可以将char[]初始化为所有的null,而不是使用for:

char date[8] = "";

or you can use memset().

或者您可以使用memset()。

#3


1  

Adding to @hmjd's find:

增加@hmjd找到:

declared at the var decls is your text pointer...

在var decls中声明是你的文本指针…

char * text;

then later...

后来……

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

Maybe try setting that 'text' pointer to something beside a random stack value will help as well.

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

Continuing the barrage, though the following will not necessarily blow up, your date variable as:

继续弹幕,尽管下面的不一定会爆炸,你的日期变量为:

char date[8];

on both client and server side The client variable isn't used at all. The server variable, however is:

在客户端和服务器端,客户端变量都没有使用。然而,服务器变量是:

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

Problem is, the date you sent is, in fact, 8 chars wide already: "12/10/12". Therefore, even if you firm-up a null terminator on the end of your string, which you should always do regardless (good practice):

问题是,你发送的日期实际上已经是8个字符了:“12/10/12”。因此,即使您的字符串末尾有一个空终止符,您也应该始终这样做(良好的实践):

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

you'll be truncating off the last char of your date.

你将会截断你约会对象的最后一个字符。

There are other things wrong with this; we've only pointed out a few. Think about sending length-prefixes with each of these data values in the array, with checks or range to ensure you get what you expected.

还有其他的问题;我们只指出了一些。考虑在数组中使用每个数据值发送长度前缀,通过检查或范围来确保得到您所期望的。

Finally, spending some time on the business-end of a debugger would probably do you very well, especially on the server side.

最后,花点时间在调试器的业务端可能会非常好,尤其是在服务器端。