简体   繁体   English

Linux上的UDP套接字; 发送成功但无法接收大缓冲区

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

I have two machines, that I would like both of them to communicate using sockets under C programming language. 我有两台机器,我希望它们都可以使用C编程语言下的套接字进行通信。

I have developed two samples to represent both sides but I noticed that I can send data successfully if they are smaller than certain number. 我已经开发了两个样本来代表双方,但是我注意到,如果它们小于特定数目,则可以成功发送数据。

The size that I have tested but does not work is sending & receiving 2048 bytes , on contrary, for other smaller sizes such as 258 Bytes, 1KByte it works fine. 我测试过但无法使用的大小是发送和接收2048字节,相反,对于其他较小的大小(例如258字节,1 KB),它可以正常工作。

After doing some investigations, I found out that, the sending operation has no errors while for the reception, I did not get any thing at all. 经过一些调查,我发现发送操作没有错误,而接收方面我什么也没收到。

I have checked the sending and receiving buffer sizes on both machines and I guess they are sufficient. 我已经检查了两台机器上的发送和接收缓冲区大小,我想它们足够了。

Here are the first side of my code: 这是我代码的第一面:

/* 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);
}

Here are the second side of my code: 这是我的代码的第二面:

#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);
}

Here is the output on first side: 这是第一面的输出:

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

Here is the output on second side: 这是第二面的输出:

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:

I am not sure what I am doing wrong here. 我不确定我在做什么错。 Do you any suggestions? 你有什么建议吗?

While UDP datagram packet size could be up to 64K (16-bit data length field), the usual underlying data link technology - ethernet - has a frame size of 1500 bytes. 尽管UDP数据报的数据包大小最大为64K(16位数据长度字段),但通常的基础数据链路技术(以太网)的帧大小为1500字节。 Less at least 20 bytes for IP header, less 8 bytes of UDP header, that leaves only 1472 bytes for UDP payload that could be sent without IP fragmentation, which usually leads to issues like in your case where packets are just dropped somewhere. IP标头至少少20个字节,UDP标头至少少8个字节,这样就留下了1472个字节用于UDP有效载荷,而这些载荷可以在没有IP分段的情况下被发送,这通常会导致出现问题,例如在数据包被丢弃到某个地方的情况下。

Most UDP-based protocols restrict datagram size for exactly this reason. 正是由于这个原因,大多数基于UDP的协议都限制了数据报的大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM