2015-10-28 56 views
2

我知道TCP中没有数据包概念,因为它是一个流套接字,那么例如,如果我有2000字节的数据包,说2000'a',并且我的默认缓冲区大小是1024,那么它应该发送两次并接收两次?有关数据包和缓冲区大小的TCP套接字编程

所以在send()函数,

iResult = send(s, sendbuf, packet_size, 0); 

第二个参数,我应该把什么?一个1024字节mallocated的发送缓冲区字符指针或一个2000字节的数据包字符指针,它会自动为我处理它?

和recv()阻塞函数,我应该把缓冲区字符指针指向第二个参数或数据包之一?

对于标题,我的朋友建议我添加4个字节的标题来存储包的信息,例如。数据包的序列号和大小,如何实现?谢谢

@Giorgi,谢谢!我也想问,如果我不做部分写入处理和while循环中的发送速度非常快(没有睡眠),那么服务器端会出现错误/丢失?为的recv()

SOCKET newsfd; 
bind(s, (struct sockaddr *)ReceiverSocket, sizeof(struct sockaddr_in)); 
if (strcmp(protocol, "tcp") == 0 || strcmp(protocol, "TCP") == 0){ 
    listen(s, 1); 
    newsfd = accept(s, 0, 0); 
} 

//*** Create Update Display Thread 
std::thread th(Function_packet_transmission_display, update_interval, (char*) "recv"); 

//*** Receive Data//*** Set Jitter 
long time_old = 0, time_new = 0, time_start = 0; 
long float jitter_new = 0, jitter_old = 0; 
long long temp_accubyte = 0, temp_pktnum = 0; //testing 
char *recvbuf = new char[buffer_size]; 
long long next_seq_num = 1; int retVal; 
do{ 

    if (strcmp(protocol, "tcp") == 0 || strcmp(protocol, "TCP") == 0){ 
     retVal = recv(newsfd, recvbuf, packet_size, 0); 
     if ((retVal == SOCKET_ERROR) || (retVal == 0)){ 
      printf("\nreturn fail code:%i\n", WSAGetLastError()); 
      closesocket(s); 
      WSACleanup(); 
      lck.lock(); 
      Ended = true; 
      lck.unlock(); 
      return 0; 
     } 
    } 
    else if (strcmp(protocol, "udp") == 0 || strcmp(protocol, "UDP") == 0){ 
     int fromlen = (int)sizeof(struct sockaddr_in); 
     retVal = recvfrom(s, recvbuf, packet_size, 0, (struct sockaddr *)ReceiverSocket, &fromlen); 
    } 
    //testing 
    temp_accubyte += retVal; 
    temp_pktnum++;//TEST 
    //printf("\racc: %lld %lld - ", temp_accubyte, temp_pktnum); 
    //if (temp_pktnum==100000)   printf("\nReach 100000\n", temp_accubyte, temp_pktnum); 

    if (timer == NULL){ 
     timer = new ES_FlashTimer(); 
    } 
+0

@Giorgi,谢谢!我也想问,如果我不做部分写入处理和while循环中的发送速度非常快(没有睡眠),那么服务器端会出现错误/丢失?对于recv() –

回答

3

如果我有一个2000个字节的数据包,说2000 'A',

你不知道。您有2000字节的消息

和我的默认缓冲区大小为1024

可能性不大。这将是至少8192,可能有成千上万K.

那么它应该发送两次

最少。

并收到两次?

至少。

对于第二个参数,我应该放什么?

消息要发送的大小:在这种情况下,2000。

发送缓冲区的字符指针与1024个字节mallocated

或2000个字节的数据包字符指针,它会自动处理一下吗?

是的。

对于recv()阻塞函数,我应该把缓冲区字符指针放在第二个参数或者数据包之一上?

我不能使这个头或尾巴,但你应该收到一个尽可能大的缓冲区,并循环,直到你有整个消息。

对于标题,我的朋友建议我添加4个字节的标题来存储包的信息,例如。数据包的序列号和大小,它如何实现!

你并不需要序列号,但消息大小是一个好主意。只要将它粘贴在信息的前面。不清楚问题在这里。

+0

正确,除了“它会自动为我处理”。您需要检查'write'或'send'调用的返回值,并处理部分写操作。 –

+0

@BenVoigt该语句仅适用于send(),并且根据Posix在阻塞模式下它是正确的,除非存在中断。 – EJP

+0

buf [输出] 指向接收传入数据的缓冲区的指针。 len [in] buf参数指向的缓冲区的长度(以字节为单位)。 由MSDN,所以对于send()的情况下,我把2000的len [in]来表示我想发送2000字节的这个缓冲区字符指针? 和recv()的情况下,我把任何数量的len [in]参数?因为如果长度小于2000,它会为我分割消息,然后等待下一个recv()? –

2

您需要sendall像here,你会(可能)需要写一个类似receivall。这里是sendall(略有修改):

#include <sys/types.h> 
#include <sys/socket.h> 

int sendall(int s, char *buf, int *len) 
{ 
    int total = 0;  // how many bytes we've sent 
    int bytesleft = *len; // how many we have left to send 
    int n = -1; 

    while(total < *len) { 
     n = send(s, buf+total, bytesleft, 0); 
     if (n <= 0) { break; } 
     total += n; 
     bytesleft -= n; 
    } 

    *len = total; 

    return (n<=0)?-1:0; // return -1 on failure, 0 on success 
} 

而且你可以在这里阅读了如何应对message framing,这是你所需要的。

+0

为什么不直接返回发送计数或-1?为什么指针参数? – EJP

+0

@EJP:我从该指南中展示了OP实现,其中说发送可能不会发送所有被告知的数据,类似于我的猜测。 –

+0

@ BenVoight它呢?我会期望-1。 – EJP