簡體   English   中英

Linux上的UDP套接字; 發送成功但無法接收大緩沖區

[英]UDP Sockets on Linux; send successfully but unable to receive large buffer

我有兩台機器,我希望它們都可以使用C編程語言下的套接字進行通信。

我已經開發了兩個樣本來代表雙方,但是我注意到,如果它們小於特定數目,則可以成功發送數據。

我測試過但無法使用的大小是發送和接收2048字節,相反,對於其他較小的大小(例如258字節,1 KB),它可以正常工作。

經過一些調查,我發現發送操作沒有錯誤,而接收方面我什么也沒收到。

我已經檢查了兩台機器上的發送和接收緩沖區大小,我想它們足夠了。

這是我代碼的第一面:

/* UDP client in the internet domain */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#define BUFF_SIZE               1800
#define MOBIPASS_L2_IP_ADDRESS  "192.168.13.53"
#define MOBIPASS_L2_PORT_NUM    12001

#define BRIDGE_IP_ADDRESS       "192.168.13.30"
#define BRIDGE_PORT_NUM         12000

#define RESTRICT_SRC_DST_NUM        1
#define TEN_MSEC                    10000

void error(const char *);
void adjustSockParam (int sockFD);

int main(int argc, char *argv[])
{
#if RESTRICT_SRC_DST_NUM

    int bridge_sock_fd = -1, n =-1;
    struct sockaddr_in server_mobipass, client_bridge;
    char buffer[BUFF_SIZE];
    char* choice = NULL;
    size_t size = 1;

    /* create socket descriptor at client machine*/
    bridge_sock_fd= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (bridge_sock_fd < 0) error("socket");

    /* *********************************************************
     * prepare source information of the socket file descriptor
     * *********************************************************
     */
    client_bridge.sin_family = AF_INET;
    client_bridge.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS) ;
    client_bridge.sin_port = htons(BRIDGE_PORT_NUM);
    if( bind( bridge_sock_fd, (struct sockaddr *) &client_bridge, sizeof ( client_bridge ) ) < 0 )
    {
        error( "bind" );
    }


    /* *********************************************************
     * prepare destination information of the socket file descriptor
     * *********************************************************
     */
    server_mobipass.sin_family = AF_INET;
    server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
    server_mobipass.sin_port = htons(MOBIPASS_L2_PORT_NUM);
    if( connect( bridge_sock_fd, (struct sockaddr *) &server_mobipass, sizeof ( server_mobipass ) ) < 0 ) {
        error("connect");
    }

    adjustSockParam(bridge_sock_fd);
    do
    {
        printf("sending traffic?[y/n]\n");
        getline(&choice,&size,stdin);
        if(*choice=='n')
            break;

        strncpy( buffer,
                    "Hello Mobipass, this is bridge :)\n",
                    sizeof(buffer));
        n = send( bridge_sock_fd, buffer, sizeof(buffer), MSG_CONFIRM  );
        if( n < 0 )
        {
            error( "send" );
        }

        assert(n == sizeof(buffer));

        usleep(TEN_MSEC);
        /*memset(buffer,0 , sizeof(buffer));

        if( recv( bridge_sock_fd, buffer, sizeof(buffer), 0 ) < 0 )
        {
            error( "recv" );
        }
        else
        {
            printf("Msg received from mobipass is:\n%s",buffer);
        }*/


    }while(*choice == 'y' || *choice == 'Y');

    close( bridge_sock_fd );

#else
   int tx_sock, n, rx_sock;
   unsigned int srv_length;
   struct sockaddr_in server_mobipass, from, server_bridge;
   char buffer[256];

   /* create socket descriptor at client machine*/
   tx_sock= socket(AF_INET, SOCK_DGRAM, 0);
   if (tx_sock < 0) error("socket");

   srv_length=sizeof(struct sockaddr_in);

   /*prepare server (peer entity) of UDP connection*/
   server_mobipass.sin_family = AF_INET;
   server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
   server_mobipass.sin_port = htons(MOBIPASS_L2_PORT_NUM);

   printf("Please enter the message: ");
   bzero(buffer,256);
   fgets(buffer,255,stdin);

   n=sendto(tx_sock,buffer,
            strlen(buffer),0,(const struct sockaddr *)&server_mobipass,srv_length);
   if (n < 0) error("Sendto");

   rx_sock= socket(AF_INET, SOCK_DGRAM, 0);
   if (rx_sock < 0) error("socket");

   server_bridge.sin_family =  AF_INET;
   server_bridge.sin_addr.s_addr = inet_addr(BRIDGE_IP_ADDRESS);
   server_bridge.sin_port = htons(BRIDGE_PORT_NUM);
   if (bind(rx_sock,(struct sockaddr *)&server_bridge,srv_length)<0)
          error("binding");

   n = recvfrom(rx_sock,buffer,256,0,(struct sockaddr *)&from, &srv_length);
   if (n < 0) error("recvfrom");

   /*print to stdout what have been received*/
   write(1,"Got an ack: ",12);
   write(1,buffer,n);





   /* close sockets */
   close(rx_sock);
   close(tx_sock);

#endif /* RESTRICT_SRC_DST_NUM */
   return 0;
}

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

void adjustSockParam (int sockFD)
{

    int option_value;
    socklen_t option_len = sizeof(option_value);

    /** Adjust Send Buffer Size**/
    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Initial SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);

    /*option_value = 2048;
    if( setsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, option_len)< 0)
    {
        error("get Socket Option error:");
    }

    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Final SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);*/

    /** Adjust Receiver Buffer Size **/
    if( getsockopt(sockFD, SOL_SOCKET, SO_RCVBUF,
               &option_value, &option_len)< 0)
        {
            error("get Socket Option error:");
        }
        printf("Initial SO_RCVBUF: option_len = %d option_value = %d\n",option_len,option_value);
}

這是我的代碼的第二面:

#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <assert.h>

#define BUFF_SIZE               1800
#define MOBIPASS_L2_IP_ADDRESS  "192.168.13.53"
#define MOBIPASS_L2_PORT_NUM    12001

#define BRIDGE_IP_ADDRESS       "192.168.13.30"
#define BRIDGE_PORT_NUM         12000

#define DUMP                        0
#define ACT_AS_STRING               0
#define RESTRICT_SRC_DST_NUM        1
#define TEN_MSEC                    10000

#if DUMP
    #define DUMP_BUFFER(buf,len)                \
    {                                           \
        int i;                                  \
        for(i = 0; i < len; i++)                \
            printf("buf[%d] = 0x%x",i,buf[i]);  \
    }
#else
    #define DUMP_BUFFER(buf,len)        printf("received len=%d\n",len)
#endif

void adjustSockParam (int sockFD);
void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
#if RESTRICT_SRC_DST_NUM
    int mobipass_sock_fd = -1;
    struct sockaddr_in server_mobipass, client_bridge;
    char buffer[BUFF_SIZE];
    int recivedBytes=-1;

    printf("size of buffer = %d\n",sizeof(buffer));
    /* create socket descriptor at client machine*/
    mobipass_sock_fd= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (mobipass_sock_fd < 0) error("socket");

    /* *********************************************************
     * prepare source information of the socket file descriptor
     * *********************************************************
     */
    client_bridge.sin_family = AF_INET;
    client_bridge.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
    client_bridge.sin_port = htons(MOBIPASS_L2_PORT_NUM);
    if( bind( mobipass_sock_fd, (struct sockaddr *) &client_bridge, sizeof ( client_bridge ) ) < 0 )
    {
        error( "bind" );
    }


    /* *********************************************************
     * prepare destination information of the socket file descriptor
     * *********************************************************
     */
    server_mobipass.sin_family = AF_INET;
    server_mobipass.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS) ;
    server_mobipass.sin_port = htons(BRIDGE_PORT_NUM);
    if( connect( mobipass_sock_fd, (struct sockaddr *) &server_mobipass, sizeof ( server_mobipass ) ) < 0 ) {
        error("connect");
    }

    adjustSockParam(mobipass_sock_fd);

    printf("waiting for message from bridge:\n");
    do{
        memset(buffer,0 , sizeof(buffer));
        recivedBytes = recv( mobipass_sock_fd, buffer, sizeof(buffer), 0 );
        if( recivedBytes  < 0 )
        {
            error( "recv" );
        }
        else
        {
            assert(recivedBytes == sizeof(buffer));
            DUMP_BUFFER(buffer,recivedBytes);
#if ACT_AS_STRING
            printf("Msg received from bridge is:\n%s",buffer);
#endif
        }
        usleep(TEN_MSEC);
#if ACT_AS_STRING
        strncpy( buffer,
                    "Hello Bridge, this is mobipass :)\n",
                    sizeof(buffer));
        if( send( mobipass_sock_fd, buffer, sizeof(buffer), 0 ) < 0 )
        {
            error( "send" );
        }
#endif
    }while(1);

    close( mobipass_sock_fd );

#else
    int tx_sock, n, rx_sock;
    unsigned int srv_length;
    socklen_t fromlen;
    struct sockaddr_in server_mobipass, from, server_bridge;
    char buf[1024];


    rx_sock=socket(AF_INET, SOCK_DGRAM, 0);
    if (rx_sock < 0) error("Opening socket");
    else printf("Creating rx udp socket\n");

    srv_length = sizeof(server_mobipass);
    bzero(&server_mobipass,srv_length);

    server_mobipass.sin_family=AF_INET;
    server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS);
    server_mobipass.sin_port=htons(MOBIPASS_L2_PORT_NUM);

    if (bind(rx_sock,(struct sockaddr *)&server_mobipass,srv_length)<0)
    error("binding");
    else
    printf("Binding a socket to a server IP address\n");
    fromlen = sizeof(struct sockaddr_in);

    tx_sock=socket(AF_INET, SOCK_DGRAM, 0);
    if (tx_sock < 0) error("Opening socket");
    else printf("Creating tx udp socket\n");

    server_bridge.sin_family=AF_INET;
    server_bridge.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS);
    server_bridge.sin_port=htons(BRIDGE_PORT_NUM);

    while (1)
    {
    printf("waiting for a message from client side:\n");
    n = recvfrom(rx_sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
    if (n < 0) error("recvfrom");

    write(1,"Message received from eNB machince:\n",36);
    write(1,buf,n);

    n = sendto(tx_sock,"hello eNB, I am mobipass\n",27,
              0,(struct sockaddr *)&server_bridge,fromlen);
    if (n  < 0) error("sendto");
    }

#endif
    return 0;
 }

void adjustSockParam (int sockFD)
{

    int option_value;
    socklen_t option_len = sizeof(option_value);

    /** Adjust Send Buffer Size**/
    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Initial SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);

/*  option_value = 2048;
    if( setsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, option_len)< 0)
    {
        error("get Socket Option error:");
    }

    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Final SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);*/

    /** Adjust Receiver Buffer Size **/
    if( getsockopt(sockFD, SOL_SOCKET, SO_RCVBUF,
               &option_value, &option_len)< 0)
        {
            error("get Socket Option error:");
        }
        printf("Initial SO_RCVBUF: option_len = %d option_value = %d\n",option_len,option_value);
}

這是第一面的輸出:

Initial SO_SNDBUF: option_len = 4 option_value = 112640
Initial SO_RCVBUF: option_len = 4 option_value = 112640
sending traffic?[y/n]
y
sending traffic?[y/n]
y

這是第二面的輸出:

size of buffer = 1800
Initial SO_SNDBUF: option_len = 4 option_value = 1048576
Initial SO_RCVBUF: option_len = 4 option_value = 1048576
waiting for message from bridge:

我不確定我在做什么錯。 你有什么建議嗎?

盡管UDP數據報的數據包大小最大為64K(16位數據長度字段),但通常的基礎數據鏈路技術(以太網)的幀大小為1500字節。 IP標頭至少少20個字節,UDP標頭至少少8個字節,這樣就留下了1472個字節用於UDP有效載荷,而這些載荷可以在沒有IP分段的情況下被發送,這通常會導致出現問題,例如在數據包被丟棄到某個地方的情況下。

正是由於這個原因,大多數基於UDP的協議都限制了數據報的大小。

暫無
暫無

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

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