2012-10-02 205 views
3

可能重复:
What is the correct way of reading from a TCP socket in C/C++?如何发送和接收数据的TCP套接字(C/C++)

我试图建立一个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); 
+0

让我猜猜,一个或所有的'recv'电话不回你问的具体数额?或者您打印的字符串没有正确终止? –

+0

不要仅仅标记一切在你脑袋里飞驰而过的东西。对UDP进行标记绝对没有任何理由,除非有非常明确的标记两者的理由,否则应该标记C或C++。 – Wug

+0

这应该是C或C++(用*标记*) – WhozCraig

回答

1

一个(重复)错误是:

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

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

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

注意,你可以初始化一个char[]所有空值,而不是使用for的:

char date[8] = ""; 

或者您可以使用memset()

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; 

你会被截断了你日期的最后一个字符。

这还有其他的错误;我们只指出了一些。考虑使用数组中的每个数据值发送长度前缀,并使用检查或范围来确保获得预期的结果。最后,花一些时间在调试器的业务端可能会很好,尤其是在服务器端。

+0

+1错过了,可能是OP正在经历的问题。 – hmjd

5

下面是一个简单的“接受所有”功能:

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