关于数据包和缓冲区大小的TCP套接字编程

TCP socket programming regarding the packet and buffer size

本文关键字:TCP 套接字 编程 数据包 缓冲区      更新时间:2023-10-16

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

所以对于send()函数,

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

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

对于recv()阻塞函数,我应该将缓冲区字符指针放在第二个参数还是数据包指针?

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

@乔治,谢谢!我还想问,如果我不进行部分写入处理,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:%in", 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 100000n", temp_accubyte, temp_pktnum);
    if (timer == NULL){
        timer = new ES_FlashTimer();
    }

如果我有一个2000字节的数据包,比如说2000‘a’,

你没有。您有一条2000字节的消息

我的默认缓冲区大小是1024

不太可能。这将是至少8192,可能成千上万的K

那么它应该发送两次

至少。

收到两次?

至少。

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

要发送的消息的大小:在本例中为2000。

发送带有1024字节错误分配的缓冲区字符指针

没有。

还是一个2000字节的数据包字符指针,它会自动为我处理它?

是的。

对于recv()阻塞函数,我应该将缓冲区字符指针放在第二个参数还是数据包指针?

我无法理解这一点,但您应该将接收到尽可能大的缓冲区中,并循环直到您获得整个消息。

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

您并不真的需要序列号,但消息大小是个好主意。把它贴在信息的前面。不清楚这里的问题是什么。

您将需要像这里一样的sendall,并且(可能)需要编写类似的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
} 

你可以在这里阅读如何处理信息框架,这正是你所需要的。