C/ c++ UDP服务器问题

C/C++ UDP Server Problem

本文关键字:服务器 问题 UDP c++      更新时间:2023-10-16

我这里有一个UDP服务器监听端口9001。我为接收数据缓冲区定义了一个最大块大小为4096。

我的问题是,当客户端发送大数据时,例如20000字节,我只收到我定义的块大小。我有一个无尽的循环,将不断从客户端接收数据。

下面是我的代码:
  void TdaServer::StartServer()
  {
      #ifdef LOGGING_ENABLED
      LOG_MSG("WARNING: StartServer called");
      #endif
       struct sockaddr_in cli;
       //int socketId;
       socklen_t size;
       socketId=socket(AF_INET, SOCK_DGRAM, 0);
       if (socketId < 0)
       {
          #ifdef LOGGING_ENABLED
          LOG_MSG("ERROR: failed to create socket!");
          #endif
       } 

       int length = sizeof(server);
       bzero(&server,length);
       server.sin_family        =AF_INET;
       server.sin_addr.s_addr   =INADDR_ANY;
       int port = atoi(Config::GetEnv("nfc_demo_port").c_str());
       if(port==0)
          port = 9001;
       server.sin_port          =htons(port);
       if (bind(socketId,(struct sockaddr *)&server,length)<0) 
       {
          #ifdef LOGGING_ENABLED
          LOG_MSG("Error binding!");
          #endif
       }
       size = sizeof(struct sockaddr_in); 
       thread_parm_t *parm=NULL;
       parm             = new thread_parm_t;
       parm->socketId   = socketId;
       parm->client     = cli;
       parm->size       = size;
       #ifdef LOGGING_ENABLED
       LOG_MSG("TDA server started, socket id: %i, port: %d", socketId, port);
       #endif
       pthread_attr_t attr;
       pthread_t clientthread;
       pthread_attr_init(&attr);
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 
       pthread_create(&clientthread, &attr, Receive, (void *)parm);
  }
  void *Receive(void *parm)
  {
    thread_parm_t *p = (thread_parm_t *)parm;
    char buffer[MAX_CHUNK_SIZE+1]; //MAX_CHUNK_SIZE = 4096
    string data="";
    extern int errno;
    while(true)
    {
        #ifdef LOGGING_ENABLED
        LOG_MSG("-TdaServer waiting for data...");
        #endif
        int n = recvfrom(p->socketId,buffer,MAX_CHUNK_SIZE,0,
                (struct sockaddr *)&p->client, &p->size); //wasn't able to receive large data ex. 20000 bytes
        #ifdef LOGGING_ENABLED
        LOG_MSG("-TdaServer received data size: %d", n);
        #endif
        if(n>0)
        {
            data = data.append(string(buffer).substr(0, n));
            #ifdef LOGGING_ENABLED
            LOG_MSG("-TdaServer [%s] n: %d < mcs: %d, %s", inet_ntoa(p->client.sin_addr), n, MAX_CHUNK_SIZE, (n<MAX_CHUNK_SIZE?"true":"false"));
            #endif
            if(n<MAX_CHUNK_SIZE)//received complete
            {
                #ifdef LOGGING_ENABLED
                LOG_MSG("-TdaServer received data size: %d, complete!", n);
                #endif
                TcbMgrConnection::SendResponse(data.c_str());
                data = "";
            }           
        }
        else if(n<0)
        {
            #ifdef LOGGING_ENABLED
            LOG_MSG("TdaServer: Error reading from socket");
            #endif
        }
        else
        {
            if(n==0)
            {
                #ifdef LOGGING_ENABLED
                LOG_MSG("IPServer: client %d disconnected", p->socketId);
                #endif              
                //break;
            }
        }
    }
    close(p->socketId);
    return NULL;
  }

这里是UDP客户端代码,用VB编写。净

Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSend.Click
    Dim pRet As Integer
    Try
        GLOIP = IPAddress.Parse(txtIP.Text)
        GLOINTPORT = txtPort.Text
        udpClient.Connect(GLOIP, GLOINTPORT)
        bytCommand = Encoding.ASCII.GetBytes(txtMessage.Text)
        pRet = udpClient.Send(bytCommand, bytCommand.Length)
        Console.WriteLine("No of bytes send " & pRet)
        txtInfo.Text = "INFORMATION" & vbCrLf & "No of bytes send " & pRet
    Catch ex As Exception
        Console.WriteLine(ex.Message)
        txtInfo.Text = txtInfo.Text & vbCrLf & ex.Message
    End Try
End Sub

我做的对吗?请帮助. .提前感谢

这就是recvfrom()的工作原理

recvfrom()函数将返回写入消息的长度到buffer参数所指向的缓冲区。为基于消息的套接字,如SOCK_RAW、SOCK_DGRAM和SOCK_SEQPACKET,整个消息应在一次操作中读取。如果消息太长以适应所提供的缓冲区,并且MSG_PEEK未在标志中设置参数时,多余的字节将被丢弃。对基于流套接字,如SOCK_STREAM,消息边界将被忽略。在在这种情况下,数据应该尽快返回给用户可用,且不得丢弃任何数据。

分配更大的缓冲区或更改客户端发送更小的数据包

从UDP套接字读取数据报。如果您给它一个小于数据报大小的缓冲区,其余部分将被丢弃。使用从下一个数据报返回的数据进一步读取。UDP不为你做任何数据的连接/分割。

最大数据报大小是64KB(在UDP报头的大小字段是16位),所以你可以发送到这个时间与单个write()/send()/sendto()调用,最有可能导致IP碎片。在接收端,您必须将接收缓冲区大小与您发送的最大大小相匹配。

我不建议发送大的UDP数据包。UDP数据包的数据大小被限制在1300字节左右(考虑到路由器的典型MTU是1500或更少),任何更大的数据都被路由器分片,然后再组装回来。

如果路上任何一个路由器不允许分片,所有的数据包将被丢弃。如果任何片段丢失,整个数据包将被丢弃,即使在许多情况下仍然可以使用其余的数据。

传输更大的块的更好方法是手动将它们分成约1250字节的块,然后在接收器上将它们粘合在一起。请记住,其中一些可能会丢失或到货时出现故障。