如何完全接收高速UDP数据包?

时间:2018-06-07 07:09:10

标签: sockets visual-c++ udp

我有一台连续发送数据的UDP服务器。我想收到服务器发送的所有数据包。

在服务器端,我有两个线程。一个线程连续从文件中读取数据并放入双端队列。另一个线程从双端队列中读取数据并连续发送到UDP客户端。客户端代码不断从服务器接收数据。

我有变量来保存服务器代码中发送的字节数和客户端代码中接收的字节数。 两者之间存在巨大差异。服务器发送大约93 MB但客户端只接收3 - 5 MB。

如何接收服务器发送的所有数据?

请在下面找到服务器和客户端代码。

服务器代码:

#define MAX_BUFFER_SIZE 1400

typedef struct
{
    T_UCHAR buffer[MAX_BUFFER_SIZE];
    DWORD buf_size;
}RAWDATA_LOG;

deque<RAWDATA_LOG>  m_RawdataLog;   

void TransmitContinuous()
{
    if (m_sock_type_tcp == SOCK_UDP)
    {
        fileReadComplete=false;
        //start data transmission thread
        pWin_thread=AfxBeginThread(StartDataTransmitThread, (LPVOID) this);
        ReadFromFile();
    }   

}


void ReadFromFile()
{
    int bytesRead=0;
    m_no_of_bytes = MAX_BUFFER_SIZE;
    BYTE input_buf[MAX_BUFFER_SIZE]={'\0'};


    GetDlgItemText(IDEBC_FILENAME,m_fileInput);


    m_InputFile=NULL;
    /*opening the file to read*/
    m_InputFile = _tfopen(m_fileInput,L"rb");
    if(m_InputFile == NULL)
    {
        AfxMessageBox(L"Unable to open the Input file");
    }
    else
    {

        while(!feof(m_InputFile))
        {
            bytesRead=fread(input_buf,1,m_no_of_bytes,m_InputFile);

            writeRawdataToDeque(input_buf,m_no_of_bytes);
            noofBytesReadfromFile+=bytesRead;

        }
        fileReadComplete=true;
    }
}


void writeRawdataToDeque(T_UCHAR *buffer,T_S32 size)
{

    T_S32 temp_size = size;
    T_S32 size_counter = 0;
    RAWDATA_LOG temp_rawDataStruct;

    while(temp_size>0)
    {
        if(temp_size <= MAX_BUFFER_SIZE)
        {
            memcpy(temp_rawDataStruct.buffer,&buffer[size_counter],temp_size);
            temp_rawDataStruct.buf_size = temp_size;
            noofBytesWrittentoDeque+=temp_size;

        }
        else
        {
            memcpy(temp_rawDataStruct.buffer,&buffer[size_counter],sizeof(temp_rawDataStruct.buffer));
            temp_rawDataStruct.buf_size = MAX_BUFFER_SIZE;
            noofBytesWrittentoDeque+=MAX_BUFFER_SIZE;
        }

        CSingleLock datalock(&m_Cs_RawDataLog);
        datalock.Lock();
        m_RawdataLog.push_back(temp_rawDataStruct);
        datalock.Unlock();


        memset(&temp_rawDataStruct,0,sizeof(temp_rawDataStruct));
        size_counter += MAX_BUFFER_SIZE;
        temp_size = temp_size - MAX_BUFFER_SIZE;
    }                                               
}

unsigned int StartDataTransmitThread (LPVOID param)
{

    RAWDATA_LOG temp_rawDataBuf;
    int byesWritten=0;
    CString tmpStr;

    while(1)
    {

        if(!m_RawdataLog.empty())
        {
            CSingleLock datalock(&m_Cs_RawDataLog);
            datalock.Lock();
            temp_rawDataBuf = m_RawdataLog.front();
            m_RawdataLog.pop_front();
            datalock.Unlock();

            //transmit the data through socket  
            byesWritten=WritetoClient(clientIp,clientPort,(const LPBYTE)&temp_rawDataBuf, MAX_BUFFER_SIZE);

            noofBytesTransmitted+=byesWritten;

        }
        else
        {
            if(fileReadComplete == true)
            {

                break;
            }
        }       
    }

    return true;
}



bool CreateServer(char ipaddr[],int port)
{
    sockaddr_in ServerSockAddr;
    WORD m_wVersionRequested;
    WSADATA m_wsaData;
    int m_wsaErr;

    ServerSockAddr.sin_addr.s_addr=inet_addr("192.168.11.80");
    ServerSockAddr.sin_family = AF_INET;
    ServerSockAddr.sin_port = htons(2011);


     m_wVersionRequested = MAKEWORD(2, 2);          
     m_wsaErr = WSAStartup(m_wVersionRequested, &m_wsaData);
     if (m_wsaErr != 0) 
     {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        MessageBox(L"WSAStartup failed with error:" + m_wsaErr);
        return 1;
     }

    SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (INVALID_SOCKET != sock)
    {


        if ( SOCKET_ERROR == bind(sock,(struct sockaddr *) & ServerSockAddr, sizeof(ServerSockAddr)))
        {
            int b= GetLastError();
            closesocket( sock );
            return false;
        }
    }
    else
    {
        closesocket( sock );
        return false;
    }

    m_hComm = (HANDLE) sock;
}


int WritetoClient(char ipaddr[],int port,BYTE buf[],int len)
{

     sockaddr_in clientSockAddr;
     int res=0;


      SOCKET s = (SOCKET) m_hComm;

      clientSockAddr.sin_addr.s_addr=inet_addr("192.168.11.80");
      clientSockAddr.sin_family = AF_INET;
      clientSockAddr.sin_port = htons(port);

      res = sendto( s, (const char *)buf, len, 0, (SOCKADDR  *) &clientSockAddr, sizeof(clientSockAddr));

      return res;
}

客户代码:

#include <stdlib.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32")

#define BUFSIZE 1000000

int _tmain(int argc, _TCHAR* argv[])
{
    SOCKET sockfd;
    int  portno, n;
    int serverlen;
    struct sockaddr_in serveraddr;
    struct hostent *server;
    char *hostname;
    char buf[BUFSIZE];
    int BytesReceived=0;
    int buff_size=1000000;

    WORD m_wVersionRequested;
    WSADATA m_wsaData;
    int m_wsaErr;

     m_wVersionRequested = MAKEWORD(2, 2);          
     m_wsaErr = WSAStartup(m_wVersionRequested, &m_wsaData);
     if (m_wsaErr != 0) 
         {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        printf("WSAStartup failed with error:");
        return 1;
     }

    /* socket: create the socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sockfd < 0) 
    {

        printf("ERROR opening socket");
    }


    else
    {
        /* build the server's Internet address */

        serveraddr.sin_family = AF_INET;

        serveraddr.sin_port = htons(2010);
        serveraddr.sin_addr.s_addr=inet_addr("192.168.11.80");



        /* send the message to the server */
        serverlen = sizeof(serveraddr);

        setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,(char *)(&buff_size), sizeof(buff_size));

        if ( SOCKET_ERROR == bind(sockfd,(struct sockaddr *) & serveraddr, sizeof(serveraddr)))
        {
            printf("Bind Error");
            int a = GetLastError();
            printf("Error ID:%d",a);
        }
        else
        {

            printf("Reading From Server:\n");

            while(1)
            {


                n = recvfrom(sockfd, buf, sizeof(buf), 0,(struct sockaddr *) &serveraddr, &serverlen);

                if (n < 0) 
                {
                    printf("ERROR in recvfrom\n");
                    int b = GetLastError();
                    printf("Error ID:%d\n",b);
                }
                else
                {

                    BytesReceived+=n;

                    TRACE("\nTotal Bytes Received:%d\n",BytesReceived);
                }

            }
        }
    }
    getchar();
    return 0;



}

1 个答案:

答案 0 :(得分:1)

我发现您的代码存在一些问题。

在服务器端,您将服务器的套接字绑定到192.168.11.80并且您也将数据包发送到192.168.11.80,而不是将它们发送到指定的任何IP地址。 ipaddr函数的WritetoClient()参数。

在客户端,您bind()将客户端套接字连接到服务器的 IP地址。

此设置仅在客户端和服务器在同一台计算机上运行时才有效。它不能在通过网络连接的多台机器之间工作。

您需要将客户端绑定到客户端自己的计算机本地的IP地址,而不是服务器的IP地址。并且您的服务器需要将数据包发送到客户端实际绑定的IP地址。

如果您想确保您的客户端仅从服务器的IP地址接收数据,而不是从可能恰好通过同一网络发送数据的其他计算机接收数据,您可以选择connect()客户端到服务器IP地址的套接字(是的,你可以使用connect()和UDP)。

bind()用于建立套接字的本地IP地址。 connect()用于建立套接字的远程/对等IP地址。

由于您(可能)未正确绑定客户端套接字,和/或(可能)未发送到正确的IP,因此您可能会收到其他地方不期望的数据。这可以解释你所看到的巨大差异。我建议让你的客户输出它实际收到的数据,这样你就可以确保它正在接收你所期望的数据,例如:

n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *) &serveraddr, &serverlen);
if (n == SOCKET_ERROR) 
{
    int b = WSAGetLastError();
    printf("ERROR in recvfrom\nError ID:%d\n",b);
}
else
{
    BytesReceived += n;
    TRACE("\nMessage Received from %s:%hu: '%.*s'", inet_ntoa(serveraddr.sin_addr), ntohs(serveraddr.sin_port), n, buf);
    TRACE("\nTotal Bytes Received: %d\n", BytesReceived);
}