zhanglong71 发表于 2013-10-04 12:57

求助,一个UDP数据转发问题!

本帖最后由 zhanglong71 于 2013-10-04 15:55 编辑

一个转发网络数据包的程序,想不通问题出在哪里!请高人指点。

实现的原理如下:
1.使用UDP协议。
登录过程如下:
2.客户端(Client)向转发服务器(Server)发送登录数据包。登录数据包中包括客户自己的ID号。
3.转发服务器(Server)将收到的登录数据包中的客户ID号及源ip+port记录下来。
客户端1向客户端2发送数据的过程如下:
4.客户端1向转发服务器发数据包,包内有源客户端ID1及目的客户端ID2。
5.转发服务器(Server)将从客户端收到的数据包中提取目的客户端ID2,以目的客户端ID2查找客户端登录时的ip+port。再将数据包发往此ip+port对应的客户端2。

执行一次数据传输后服务器端的数据如下:
receiving ...
received !
Client Node created ok!
send login ACK ok
Client login
receiving ...
received !
Client Node created ok!
send login ACK ok
Client login
receiving ...
received !
received data !
ready to forward data !
forward data from to !
receiving ...
received !
received data !
ready to forward data !
forward data from to !
receiving ...

其中:start.c-333表示客户端登录时的ID号及ip:port。
   start.c-258表示数据从客户端1发往客户端2时的ID号:ip:port

问题:
  1.比较与的信息后发现,登录时的ip地址与需要转发数据时找到的ip地址不同:
登录时的节点信息是“22345678901: 192.168.1.112: 9655”。而转发需要数据时,找到的节点信息却是“22345678901-192.168.1.103:9655”,两者的ip地址不同
似乎处错打印了源端的ip地址信息。但找不到哪里有问题。
    2.这种数据转发及从recvfrom()中取得数据包的源ip+port的方式是否可行?

附代码如下:#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#if 1
#include "ptype.h"
#include "rbtree.h"
//#include "read.h"
#include "parse.h"
#endif

/*
*receive data as recv port
*/

int insertImsi(struct rb_root *root, struct clientNode_s *__clientNode, charsCmp_t cmp)
{
    struct rb_node **new = &(root->rb_node), *parent = NULL;

    /* Figure out where to put new node */
    while (*new)
    {
      //struct mytype *this = container_of(*new, struct mytype, node);
      struct clientNode_s *clientNode = container_of(*new, struct clientNode_s, node);
      int result = cmp(__clientNode->clientImsi, clientNode->clientImsi);

      parent = *new;
      if (result < 0)
            new = &((*new)->rb_left);
      else if (result > 0)
            new = &((*new)->rb_right);
      else
            return 0;
    }

    /* Add new node and rebalance tree. */
    rb_link_node(&(__clientNode->node), parent, new);
    rb_insert_color(&(__clientNode->node), root);

    return 1;
}

int insertClientId(struct rb_root *root, struct clientNode_s *__clientNode, cmp_t cmp)
{
    struct rb_node **new = &(root->rb_node), *parent = NULL;

    /* Figure out where to put new node */
    while (*new)
    {
      //struct mytype *this = container_of(*new, struct mytype, node);
      struct clientNode_s *clientNode = container_of(*new, struct clientNode_s, node);
      int result = cmp(__clientNode->clientId, clientNode->clientId);

      parent = *new;
      if (result < 0)
            new = &((*new)->rb_left);
      else if (result > 0)
            new = &((*new)->rb_right);
      else
            return 0;
    }

    /* Add new node and rebalance tree. */
    rb_link_node(&(__clientNode->node), parent, new);
    rb_insert_color(&(__clientNode->node), root);

    return 1;
}


struct clientNode_s *searchClientId(struct rb_root *root, unsignedint __clientId, cmp_t cmp)
{
    struct rb_node *node = root->rb_node;
    while (node)
    {
      struct clientNode_s *clientNode = container_of(node, struct clientNode_s, node);
      int result = cmp(__clientId, clientNode->clientId);
      if (result < 0)
            node = node->rb_left;
      else if (result > 0)
            node = node->rb_right;
      else
            return clientNode;
    }   
    return NULL;
}

struct clientNode_s *searchImsi(struct rb_root *root, char* __imsi, charsCmp_t cmp)
{
    struct rb_node *node = root->rb_node;
    while (node)
    {
      struct clientNode_s *clientNode = container_of(node, struct clientNode_s, node);
      int result = cmp(__imsi, clientNode->clientImsi);
      if (result < 0)
            node = node->rb_left;
      else if (result > 0)
            node = node->rb_right;
      else
            return clientNode;
    }   
    return NULL;
}

unsigned int uicmp(const unsigned int __arg1, const unsigned int __arg2)
{
    return (__arg1 - __arg2);
}

#if 1
#if 1
int charsCmp(const char* __arg1, const char* __arg2)
{
    int i;
    for(i = 0; ((i < __arg1) && (i < CIMSI_LEN)); i++)   /** Note: arg1 is the length of string **/
    {
      if(__arg1 != __arg2)
      {
            return__arg1 - __arg2;
      }
    }
    return 0;
}
#else
unsigned int charsCmp(const char* __arg1, const char* __arg2, int __len)
{
    for(int i = 0; (i < CIMSI_LEN) && (i < __len); i++)
    {
      if(__arg1 != __arg2)
      {
            return__arg1 - __arg2;
      }
    }
    return 0;
}
#endif

#else
unsigned int charsCmp(const char* __arg1, const char* __arg2)
{
    int i;

    if(__arg1 != __arg2)      /** 先比较长度 **/
    {
      return__arg1 - __arg2;
    }
   
    for(i = 1; (i < CIMSI_LEN) && (i < __arg1); i++)
    {
      if(__arg1 != __arg2)
      {
            return__arg1 - __arg2;
      }
    }
    return 0;
}
#endif

int        main(int argc, char *argv[])
{
        //int i;
        int sock_fd;
        //int iLen = 0;
        struct sockaddr_in myaddr;
        struct sockaddr_in src_addr;
        struct sockaddr_in dst_addr;

    struct clientNode_s *dstNode;
    struct clientNode_s *srcNode;

    char dstImsi;
    char srcImsi;
        char format;
    //unsigned int dstClientId = 0;
    //unsigned int srcClientId = 0;

    struct rb_root root = RB_ROOT;
        char buf;
        char value;
        int iStrLen = 0;
        int        recv_num;
        int        recvlen;

        if(2 > argc)
        {
                printf("argc\n");
                exit(1);
        }

        if(-1 == (sock_fd = socket(PF_INET, SOCK_DGRAM, 0)))
        {
                printf("socket\n");
                exit(2);
        }

        myaddr.sin_family = AF_INET;
        myaddr.sin_port = htons(atoi(argv));
        myaddr.sin_addr.s_addr = htonl(INADDR_ANY);

        if(-1 == bind(sock_fd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)))
        {
                perror("bind");
                exit(1);
        }

    while(1)
    {
      fprintf(stderr, "[%s-%d]receiving ... \n", __FILE__, __LINE__);
      recvlen = sizeof(struct sockaddr_in);
      bzero(buf, BUF_LEN);
      recv_num = recvfrom(sock_fd, (char *)buf, sizeof(buf), 0,
                (struct sockaddr *)&src_addr, (socklen_t *)&recvlen);

      fprintf(stderr, "[%s-%d]received ! \n", __FILE__, __LINE__);
      if(recv_num != -1)
      {
            iStrLen = strlen(buf);
            iStrLen = iStrLen > recv_num? iStrLen:recv_num;

            memcpy(value, buf, iStrLen);
            parsePacketFormatId(value, format);

            memcpy(value, buf, iStrLen);
            parseSrcImsi(value, srcImsi);

            memcpy(value, buf, iStrLen);
            parseDstImsi(value, dstImsi);

            if((strcmp(format, "data-send") == 0) || (strcmp(format, "data-ACK") == 0))
            {
                fprintf(stderr, "[%s-%d]received data !\n", __FILE__, __LINE__);
                //dstNode = searchImsi(&root, srcImsi, strcmp);
                dstNode = searchImsi(&root, dstImsi, strcmp);
                if(NULL != dstNode)
                {
                  /** received data and find the destination node, forward data **/
                  fprintf(stderr, "[%s-%d]ready to forward data !\n", __FILE__, __LINE__);

                  dst_addr.sin_family = AF_INET;
                  dst_addr.sin_port = dstNode->port;
                  dst_addr.sin_addr.s_addr = inet_addr(dstNode->loginAddr);
                  //memcpy(&dst_addr, dstNode->ipAddr, sizeof(dst_addr));

                  //int ret = sendto(sock_fd, buf, BUF_LEN, 0, (struct sockaddr *)dstNode->ipAddr, sizeof(struct sockaddr_in));
                  int ret = sendto(sock_fd, buf, BUF_LEN, 0, (struct sockaddr *)&dst_addr, sizeof(struct sockaddr_in));
                  if(-1 == ret)
                  {
                        fprintf(stderr, "[%s-%d]send data error !\n", __FILE__, __LINE__);
                        exit(2);
                  }
                #if 1
                  fprintf(stderr, "[%s-%d]forward data from [%s-%s:%u] to [%s-%s:%u]!\n",
                            __FILE__, __LINE__,
                            srcImsi,
                            inet_ntoa(src_addr.sin_addr),
                            src_addr.sin_port,
                            dstImsi,
                            inet_ntoa(dst_addr.sin_addr),
                            dst_addr.sin_port);
                #endif                     
                }
                else
                {
                  fprintf(stderr, "[%s-%d]destination[%s] is not on line!\n", __FILE__, __LINE__, dstImsi);
                }
            }
            else if(strcmp(format, "login-request") == 0)       /** 登录请求,记录信息 **/
            {
                /** received login message **/
                srcNode = searchImsi(&root, srcImsi, strcmp);
                if(NULL == srcNode)
                {
                  /** create new node **/
                  srcNode = malloc(sizeof(struct clientNode_s));
                  if(NULL != srcNode)
                  {
                        bzero(srcNode, sizeof(struct clientNode_s));
                        memcpy(srcNode->clientImsi, srcImsi, CIMSI_LEN);
                        memcpy(srcNode->ipAddr, &src_addr, sizeof(src_addr));
                        srcNode->clientStatus = STATUS_LGINSUC;/** 进入登录状态 **/

                        insertImsi(&root, srcNode, strcmp);

                        fprintf(stderr, "[%s-%d]Client Node[%s-%s:%u] created ok!\n",
                              __FILE__, __LINE__,
                              srcImsi,
                              inet_ntoa(src_addr.sin_addr),
                              src_addr.sin_port);

                  }
                  else
                  {
                        fprintf(stderr, "[%s-%d]malloc error. Client Node[%s] created failed!\n", __FILE__, __LINE__, srcImsi);
                  }
                }
                else
                {   
                  srcNode->clientStatus = STATUS_LGINSUC;/** 进入登录状态 **/

                  memcpy(srcNode->clientImsi, srcImsi, CIMSI_LEN);
                  memcpy(srcNode->ipAddr, &src_addr, sizeof(src_addr));
                  fprintf(stderr, "[%s-%d]Client[%s-%s:%u] login again !\n",
                            __FILE__, __LINE__,
                            srcImsi,
                            inet_ntoa(src_addr.sin_addr),
                            src_addr.sin_port);
                }

                setPacketFormat(buf, "login-ok");
                int ret = sendto(sock_fd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_in));
                if(-1 == ret)
                {
                  perror("sendto");
                  fprintf(stderr, "[%s-%d]sendto error !!!!!!\n", __FILE__, __LINE__ );
                  //exit(2);
                }
                else
                {
                  fprintf(stderr, "[%s-%d]send login ACK ok\n", __FILE__, __LINE__ );
                }
                /**
               * store the client
               **/
                strcpy(srcNode->loginAddr, inet_ntoa(src_addr.sin_addr));
                srcNode->port = src_addr.sin_port;
                           
                fprintf(stderr, "[%s-%d]Client [%s: %s: %d] login \n",
                        __FILE__, __LINE__,
                        srcImsi,
                        inet_ntoa(((struct sockaddr_in *)(srcNode->ipAddr))->sin_addr),
                        ((struct sockaddr_in *)(srcNode->ipAddr))->sin_port);

            }
            else if(strcmp(format, "login-out") == 0)
            {
                fprintf(stderr, "[%s-%d]Client[%s] logout!\n", __FILE__, __LINE__, srcImsi);
            }
            else
            {
                fprintf(stderr, "[%s-%d]buf[%s] is unrecognized!!!\n", __FILE__, __LINE__, buf);
            }
      }
    }
        close(sock_fd);

    return0;
}

zhanglong71 发表于 2013-10-04 17:59

本帖最后由 zhanglong71 于 2013-10-04 22:12 编辑

在代码第257-264行之间加入打印节点信息的语句,两者显示的数据居然不一样!
显示结果如下:
ready to forward data !

forward data from to !


代码如下:      
     printNode(dstNode);
                  fprintf(stderr, "[%s-%d]forward data from [%s-%s:%u] to [%s-%s:%u]!\n",
                            __FILE__, __LINE__,
                            srcImsi,
                            inet_ntoa(src_addr.sin_addr),
                            src_addr.sin_port,
                            dstImsi,
                            inet_ntoa(((struct sockaddr_in *)(dstNode->ipAddr))->sin_addr),
                            ((struct sockaddr_in *)(dstNode->ipAddr))->sin_port);
                  printNode(dstNode); 中间一次打印的dstNode的内容居然与前后两次的内容不一样!

其中的printNode如下:void printNode(struct clientNode_s *clientNode)
{
    if(clientNode != NULL)
    {
      printf("[%s-%s:%u]\n",
                clientNode->clientImsi,
                inet_ntoa(((struct sockaddr_in *)(clientNode->ipAddr))->sin_addr),
                ((struct sockaddr_in *)(clientNode->ipAddr))->sin_port);
    }
    else
    {
      printf("null\n");
    }
}
---------------------------------------------------------------------------------
打印信息不同的问题已解决。很可能是这样的原因:不能在printf打印语句中两次调用inet_ntoa()。
原因是inet_ntoa()会将执行的结果保存在一个静态存贮区,并返回此存贮区的地址。两次调用inet_ntoa()后,inet_ntoa()可能返回的都是同一个地址,但其中的内容只是最后一次处理后的内容。
另一个问题作备忘:手机上的客户端收不到转发的数据。用wireshark抓包发现,转发往手机的数据包长度已经超过1500Bytes。实际的包内有用信息大小不超过200。通过计算包内字符串长度,并只发送该长度的数据,手机上可以正常显示收到的数据。具体修改L250的BUF_LEN改成strlen(buf) + 1。

jonas_mao 发表于 2013-10-08 16:16

LZ good boy
页: [1]
查看完整版本: 求助,一个UDP数据转发问题!