簡體   English   中英

如何僅使用單個端口減少UDP套接字通信中的消息丟失?

[英]How to reduce message dropping in UDP socket communication, using only single port?

我有UDP客戶端和服務器的writter代碼段。 我正在使用相同的端口進行發送和接收。 我的問題是客戶端上有很多消息丟棄,因此有人可以幫助我優化代碼,這是我的UDP客戶端代碼:

#define SERVERIP "192.168.170.155"
#define SERVERPORT 5000
#define DEVICE_SEND_PORT 5000
#define DEVICE_RECEIVE_PORT 5000
#define BUFFERSIZE 2048

/**For socket file descriptor identification*/
#define S1READY 0x01

int m_SendSocketId;
int m_ReceiveSocketId;
int msgcount;
int socketbuffsize = 1*1024*1024;


/**
* FUNCTION NAME : waitToRead
* Implementation of select and non-blocking socket mechanism
* @param socket Socket that needs to be in select and non blocking mode
* @return Returnd the file descriptors which, returned by select function
*/
int waitToRead(int socket)
{
    fd_set fds;
    struct timeval timeout;
    int rc; // number of file descriptor returned
    int result; // result 
    int fd; // file descriptor

    fd=fcntl(socket,F_GETFL,0);
    fcntl(socket,F_SETFL,fd | O_NONBLOCK);

    // Set time limit. 
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    // Create a descriptor containing our sockets.
    FD_ZERO(&fds);
    FD_SET(socket, &fds);
    rc = select(sizeof(fds)*8, &fds, NULL, NULL, &timeout);
    if (rc==-1)
    {
        printf("[%s:%d#%s] Select Failed\n",__FILE__, __LINE__,__func__);
        return -1;
    }

    result = 0;
    if (rc > 0)
    {
        if (FD_ISSET(socket, &fds))
            result |= S1READY;
    }
    return result;
}
/**
* FUNCTION NAME : receiveMessage
* This function opens particular port that is defined in the 
* Configuration file, and listens on that port.
* @return if there'll be any issue in listening, then it will return 
* false otherwise it will return true.
*/
bool receiveMessage()
{
    struct sockaddr_in serverAddr; //Information about the Device UDP Server
    struct sockaddr_in client_addr; // Information about Qgate Server
    char buffer[BUFFERSIZE]; // Buffer to store incoming message
    int addr_len; // to store client address length 
    int serverlen; // to store server address length
    int sockResult; // to store result given by waitToRead
    int optval = 1;
    int receivedByte = 0;

    //Open a datagram Socket
    if((m_ReceiveSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        printf("[%s:%d#%s] UDP Client - socket() error\n",__FILE__, __LINE__,__func__);
        return false;
    }

    //Configure Server Address.
    //set family and port
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(DEVICE_RECEIVE_PORT);


    setsockopt(m_ReceiveSocketId, SOL_SOCKET,SO_REUSEADDR, &optval, sizeof(optval));

    /*if (setsockopt(m_ReceiveSocketId, SOL_SOCKET, SO_RCVBUF, &socketbuffsize, sizeof(socketbuffsize)) == -1) 
    {
        printf("Recieve Socket memory Allocation fail\n");
    }*/

    if((serverAddr.sin_addr.s_addr = INADDR_ANY) == (unsigned long)INADDR_NONE)
    {

        printf("[%s:%d#%s] Host Not found(%d)\n",__FILE__, __LINE__,__func__,h_errno);
        close(m_ReceiveSocketId); // close the socket
        return false;
    }

    if (bind(m_ReceiveSocketId, (struct sockaddr *) &serverAddr,sizeof(struct sockaddr_in)) < 0 )
    {
        printf("[%s:%d#%s] UDP Client- Socket Bind error=%s\n",__FILE__, __LINE__,__func__,strerror(errno));
        close(m_ReceiveSocketId); // close the socket
        return false;
    }

    serverlen = (int )sizeof(serverAddr);
    addr_len = sizeof(struct sockaddr); 
    // Loop and listen for incoming message 
    while(1)
    {
        //wait at select to, read
        sockResult = waitToRead(m_ReceiveSocketId);

        if(sockResult == S1READY)
        {
            receivedByte = read(m_ReceiveSocketId,buffer,BUFFERSIZE);   
            buffer[receivedByte] = '\0';

            if(receivedByte == -1)
            {
                printf("[%s:%d#%s] UDP Client - receive error", __FILE__,__LINE__,__func__);
                close(m_ReceiveSocketId);
                return false;
            }
            else if(receivedByte > 0)
            {
                //printf("[%s:%d#%s] received message = %d bytes\n",__FILE__,__LINE__,__func__,(int)strlen(buffer));
                printf("count: %d, buffer %s \n", msgcount++, buffer);
            }
        }

        memset(buffer, 0, BUFFERSIZE);
        fflush(stdout);
    }

    close(m_ReceiveSocketId); // close the socket
    printf("[%s:%d#%s] Recieve socket closed:%s\n",
                            __FILE__, __LINE__,__func__, strerror(errno));
    return true;
}


bool sendMessage(char *message)
{
    struct sockaddr_in  serverAddr; //Information about the server
    struct sockaddr_in deviceAddr; //Device UDP Client Address for sending message
    int optval = 1;

    //Open a datagram Socket
    if((m_SendSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        printf("[%s:%d#%s] UDP Client - socket() error\n",__FILE__, __LINE__,__func__);
        return false;
    }

    // Clear out the device struct
    memset(&deviceAddr, 0x00, sizeof(struct sockaddr_in));

    deviceAddr.sin_family = AF_INET;
    deviceAddr.sin_port = htons(DEVICE_SEND_PORT);

    setsockopt(m_SendSocketId, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

    /*if (setsockopt(m_SendSocketId, SOL_SOCKET, SO_SNDBUF, &socketbuffsize, sizeof(socketbuffsize)) == -1) 
    {
        printf("send Socket memory Allocation fail\n");
    }*/

     if((deviceAddr.sin_addr.s_addr = INADDR_ANY) == (unsigned long)INADDR_NONE)
    {
        // in netdb.h 
        printf("[%s:%d#%s] Host Not found(%d)\n",__FILE__, __LINE__,__func__,  h_errno);
        close(m_SendSocketId); // close the socket
        return false;
    }

    if (bind(m_SendSocketId, (struct sockaddr *) &deviceAddr,sizeof(struct sockaddr_in)) < 0 )
    {
        printf("[%s:%d#%s] UDP Client- Socket Bind error=%s\n",__FILE__, __LINE__,__func__,strerror(errno));
        close(m_SendSocketId); // close the socket
        return false;
    }


    // Clear out the server struct
    memset(&serverAddr, 0x00, sizeof(struct sockaddr_in));

    //Configure Server Address.
    //set family and port
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVERPORT);
    //serverAddr.sin_addr.s_addr = htonl(39898);

    if((serverAddr.sin_addr.s_addr = inet_addr(SERVERIP)) == (unsigned long)INADDR_NONE)
    {
        printf("[%s:%d#%s] Host Not found %d\n",__FILE__, __LINE__,__func__,h_errno);
        close(m_SendSocketId);
        return false;
    }

    // Send data to the server.
    if( sendto(m_SendSocketId, message,strlen(message) ,0, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0 )
    {
        printf("[%s:%d#%s] UDP Client - sendto() error=%s \n",__FILE__, __LINE__,__func__,strerror(errno));
        close(m_SendSocketId);  
        return false;
    }

    close(m_SendSocketId);
    return true;
}

int main ()
{
    int loop;
    char str[10];
    msgcount = 1;   
    pthread_t receiveThread;

    if(pthread_create(&receiveThread, NULL,(void *)&receiveMessage, NULL) != 0)
    {
        printf("[%s:%d#%s] thread create Failed(%s)\n",
            __FILE__, __LINE__,__func__, strerror(errno));
        return false;
    }

    for(loop =0; loop < 1000; loop++)
    {
        sprintf(str,"%4d",loop);
        sendMessage(str);   
    }

    pthread_join(receiveThread, NULL);  
    return 0;
}

這是臨時的UDP服務器代碼,它接收幾乎90%以上的消息,並發送相同的消息,但是udpclient無法接收消息。

int main()
{
        int sock;
        int addr_len, bytes_read, bytes_send;
        char recv_data[1024];
        int i;
        int count=0;
        struct sockaddr_in server_addr , client_addr;


        if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
            perror("Socket");
            exit(1);
        }

        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(5000);
        server_addr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(server_addr.sin_zero),8);

        //client_addr.sin_family = AF_INET;

        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

        if (bind(sock,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
        {
            perror("Bind");
            exit(1);
        }

        addr_len = sizeof(struct sockaddr);

        printf("\nUDPServer Waiting for client on port 5000");
        fflush(stdout);

    while (1)
    {
        bytes_read = recvfrom(sock,recv_data,1024,0,(struct sockaddr *)&client_addr, (socklen_t *)&addr_len);
        recv_data[bytes_read] = '\0';


        if(recv_data[0]!=0x07)
        {
            recv_data[0] = 0x09;
            //client_addr.sin_port = htons(51254);

            bytes_send = sendto(sock, recv_data, bytes_read, 0, (struct sockaddr *)&client_addr, (socklen_t)sizeof(client_addr));
            if(bytes_send < 0 )
            {
                perror("send to ");
            }
            printf("\nNumber  %d", ++count);
            memset(&recv_data, 0x00, 1024);

        }
        else
        {
            printf("Received Keep ALive\n");        
        }
        memset(&client_addr, 0x00, sizeof(struct sockaddr_in));

        fflush(stdout);

    }
    return 0;
}

任何幫助將不勝感激。 感謝Yuvi

您的代碼與UDP丟棄數據包無關,除了可能是因為對於網絡或接收方而言,數據包發送速度太快。 UDP不可靠。 它丟棄數據包。 如果您的應用程序協議不需要丟棄的數據包,則必須通過基於ACK或基於NACK的協議重試來建立該級別的可靠性。

或者在這種情況下像其他人一樣使用TCP。

問題出在sendMessage函數中,在這里我每次需要發送消息時都會重新創建套接字,我認為這需要時間。 我還不知道哪個呼叫阻塞了,但是發送套接字解決了我的問題。 現在,丟棄的消息最多僅為20%到30%。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM