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

时间:2013-01-02 12:29:24

标签: c sockets

我有两台机器,我希望它们都能在C编程语言下使用套接字进行通信。

我已经开发了两个代表双方的样本,但我注意到如果数据小于一定数量,我可以成功发送数据。

我测试但不起作用的尺寸是发送&相反,接收2048字节,对于其他较小的大小,如258字节,1KByte它工作正常。

在做了一些调查后,我发现,发送操作没有错误,而接收时,我根本没有得到任何东西。

我检查了两台机器上的发送和接收缓冲区大小,我猜它们就足够了。

以下是我的代码的第一面:

/* 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:

我不确定我在这里做错了什么。你有什么建议吗?

1 个答案:

答案 0 :(得分:1)

虽然UDP数据报数据包大小可能高达64K(16位数据长度字段),但通常的基础数据链接技术 - ethernet - 的帧大小为1500字节。 IP报头少至少20个字节,少于8个字节的UDP报头,只留下1472个字节用于UDP有效负载,可以在没有IP分段的情况下发送,这通常会导致类似于丢弃数据包的问题。

大多数基于UDP的协议正是出于这个原因限制数据报大小。