免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 14234 | 回复: 12
打印 上一主题 下一主题

[函数] recvfrom 函数的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-31 21:56 |只看该作者 |倒序浏览
第一次用网络编程,使用了原始套接字的UDP。想实现的功能是服务器接受到来自客户端的数据然后返回给客户端,但是会出现以下问题:
(1)在recvfrom函数接时,得到的客户端的地址信息(struct sockaddr_in client)中的端口号为0,以至于,服务器返回数据的sendto函数不能执行成功。
(2)只要服务器接收到来自客户端的信息,客户端就不停的在循环、不停的打印出消息,而且消息的内容始终是第一条的消息。

代码如下所示,请各位指正!谢谢!
  1. //头文件header.h
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <netdb.h>

  7. #include <sys/types.h>

  8. #include <netinet/in.h>
  9. #include <netinet/ip.h>
  10. #include <netinet/udp.h>

  11. #include <sys/socket.h>

  12. #include <sys/wait.h>

  13. #include <unistd.h>

  14. #include <pthread.h>
  15. //#include <linux/ip.h>

  16. #define IP_HEAD_LEN                20                        //IP header length
  17. #define UDP_HEAD_LEN        8                        //UDP header length
  18. #define PACKET_LEN                1500                //Packet length(decided by ethnet packet length)
  19. #define UDP_LEN                        PACKET_LEN - IP_HEAD_LEN        //UDP length(include UDP head and data)
  20. #define MSG_LEN                 UDP_LEN - UDP_HEAD_LEN                //paylod length(data)
  21. #define SERVER_PORT                4567                //server default port
  22. #define CLIENT_PORT                4567                //client default port
  23. #define MAX_ROUTE_HOP        64                        //Max route hops
  24. #define MAX_USER                5
  25. /*
  26. *user information structure
  27. */
  28. typedef struct user
  29. {
  30.         int sockfd;
  31.         struct sockaddr_in addr;
  32. }USER;

  33. /* Pseudo Header Structure */
  34. typedef struct psd_hdr                                //定义UDP/TCP伪报头
  35. {
  36.         struct in_addr saddr;                                //源地址
  37.         struct in_addr daddr;                                //目的地址
  38.         unsigned char mbz;                                        //全零
  39.         unsigned char proto;                                //协议类型
  40.         unsigned short len;                                //UDP/TCP长度
  41. }PSD_HEADER;

  42. /* UDP Header Structure */
  43. typedef struct _udphdr                                //定义UDP报头
  44. {
  45.         unsigned short uh_sport;                        //16位源端口
  46.         unsigned short uh_dport;                        //16位目的端口
  47.         unsigned short uh_len;                                //16位长度
  48.         unsigned short uh_sum;                                //16位校验和
  49. }UDP_HEADER;

  50. /* TCP Header Structure
  51. */
  52. typedef struct _tcphdr                                //定义TCP报头
  53. {
  54.         unsigned short th_sport;                        //16位源端口
  55.         unsigned short th_dport;                        //16位目的端口
  56.         unsigned int th_seq;                                //32位序列号
  57.         unsigned int th_ack;                                //32位确认号
  58.         unsigned char th_lenres;                        //4位首部长度/4位保留字
  59.         unsigned char th_flag;              //6位标志位
  60.         unsigned short th_win;                                //16位窗口大小
  61.         unsigned short th_sum;                                //16位校验和
  62.         unsigned short th_urp;                                //16位紧急数据偏移量
  63. }TCP_HEADER;

  64. /*IP HEADER Structure
  65. */
  66. typedef struct _iphdr                             //定义IP报头
  67. {
  68.         unsigned char h_lenver;                                        //version and header len
  69.         unsigned char tos;                                                //type of service        8bit
  70.         unsigned short t_len;                                //total length                16bit
  71.         unsigned short id;                                        //identification        16bit
  72.         unsigned short off;
  73.         unsigned char ttl;
  74.         unsigned char proto;
  75.         unsigned short sum;
  76.         struct in_addr srcIP;
  77.         struct in_addr dstIP;
  78. }IP_HEADER;

  79. //服务器
  80. #include "header.h"

  81. static unsigned short checksum(int numwords, unsigned short *buff);
  82. void RemovHead(int type, char *buf);
  83. struct sockaddr_in user[MAX_USER];                //user structure array

  84. int main()
  85. {
  86.         int sockfd,i; //i用作循环
  87.         struct sockaddr_in server,client;
  88.         struct hostent *ht;
  89.         IP_HEADER iphead;
  90.         UDP_HEADER udphead;
  91.         PSD_HEADER psdhead;
  92.         struct in_addr my_addr;

  93.     struct in_addr serv_addr;

  94.         char hostname[20],qstr[] = "quit";
  95.         char msg_tx[PACKET_LEN],buf[PACKET_LEN];                /*message and buffer to send */
  96.         char msg_rx[PACKET_LEN];
  97.         int on=1;
  98.         int add_len = sizeof(struct sockaddr);

  99.         for(i=0; i<MAX_USER; i++)
  100.         {
  101.                 user[i].sin_addr.s_addr = 0;
  102.         }
  103.        
  104.         printf("\nEnter the server's IP:\n");
  105.         scanf("%s",hostname);
  106.        
  107.         //创建原始套接字
  108.         if((sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_UDP)) == -1)
  109.         {
  110.                 perror("socket");
  111.                 exit(1);
  112.         }
  113.        
  114.         //设置套接字选项
  115.         if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,&on, sizeof(on)) < 0)
  116.         {
  117.                 printf("setsockopt error!\n");
  118.                 close(sockfd);
  119.                 exit(1);
  120.         }

  121.         //获得host信息
  122.         if((ht = gethostbyname(hostname)) == NULL)
  123.         {
  124.                 perror("gethostbyname");
  125.                 exit(1);
  126.         }
  127.        
  128.         //填充sockaddr_in结构体
  129.         memcpy(&server.sin_addr,ht->h_addr,ht->h_length);        
  130.         server.sin_family = AF_INET;
  131.         server.sin_port=htons(SERVER_PORT);
  132.         bzero(&(server.sin_zero),8);
  133.        
  134.         //帮定套接字
  135.         if(bind(sockfd, (struct sockaddr*)&server,sizeof(server)) < 0)
  136.         {
  137.                 perror("bind");
  138.                 exit(1);
  139.         }
  140.         printf("socket success...\n");
  141.        
  142.         //ip头部填充
  143.         iphead.h_lenver = (4<<4|sizeof(IP_HEADER)/sizeof(unsigned long));
  144.     iphead.tos = 0;
  145.     iphead.id  = htons((unsigned short)rand());
  146.     iphead.off = 0;
  147.     iphead.ttl = MAX_ROUTE_HOP;
  148.     iphead.proto  = IPPROTO_UDP;
  149.     iphead.sum = 0;
  150.     iphead.srcIP = server.sin_addr;                //测试用的环路地址127.0.0.1
  151.     iphead.dstIP = server.sin_addr;
  152.    
  153.     //udp头部填充
  154.     udphead.uh_sport = htons(CLIENT_PORT);
  155.     udphead.uh_dport = htons(SERVER_PORT);
  156.     udphead.uh_sum = 0;
  157.    
  158.     //udp伪首部填充
  159.     psdhead.saddr = iphead.srcIP;
  160.     psdhead.daddr = iphead.dstIP;
  161.     psdhead.mbz = 0;
  162.     psdhead.proto = iphead.proto;

  163.     //接收消息
  164.     printf("You can receive data now!\n");
  165.     int len = -1;
  166.     int msg_rx_num = 0;
  167.     int msg_tx_num = 0;
  168.    
  169.     IP_HEADER *pip = (IP_HEADER*)malloc(sizeof(IP_HEADER));
  170.         UDP_HEADER *pudp = (UDP_HEADER*)malloc(sizeof(UDP_HEADER));
  171.         while(1)
  172.         {
  173.                 //usleep(2000000);
  174.                 memset(msg_rx, 0, MSG_LEN);

  175.                    memset(buf, 0, MSG_LEN);
  176.                 len = recvfrom(sockfd,msg_rx,sizeof(msg_rx),0,(struct sockaddr*)&client,&add_len);
  177.                 if(len < 0)
  178.                 {
  179.                         printf("不是来自rawclient的消息");
  180.                 }
  181.                 else
  182.                 {
  183.                         printf("\nsockfd =%d----------------------------------------------------\n",sockfd);
  184.                         printf("\n客户端口:%d",client.sin_port);
  185.                         printf("\t客户IP:%d",client.sin_addr.s_addr);

  186.                         /*打印、调试============================================================*/
  187.                         pip = (IP_HEADER*)msg_rx;
  188.                         pudp = (UDP_HEADER*)(msg_rx + pip->t_len);

  189.                         printf("协议:%d,校验和:%d\n",pip->proto,pip->sum);
  190.                         printf("源地址:%d",pip->srcIP.s_addr);
  191.                         printf("\t目的地址:%d\n",pip->dstIP.s_addr);
  192.                         printf("源端口:%d,目的端口:%d,长度:%d\n",
  193.                                         ntohs(pudp->uh_sport),ntohs(pudp->uh_dport),ntohs(pudp->uh_len));
  194.                        
  195.                         char tmp[MSG_LEN];
  196.                         memcpy(buf,msg_rx+sizeof(IP_HEADER)+sizeof(UDP_HEADER),sizeof(buf));
  197.                         printf("接收到第%d条消息:%s\n",msg_rx_num++,buf);

  198.                         //转发=========================
  199.                         char *ptr = msg_tx;
  200.                         memset(msg_tx, 0, MSG_LEN);
  201.                         iphead.t_len = htons(sizeof(IP_HEADER)+sizeof(UDP_HEADER)+strlen(buf));
  202.                         udphead.uh_len = htons(sizeof(UDP_HEADER)+strlen(buf));
  203.                         psdhead.len = udphead.uh_len;

  204.                         //组包、发送
  205.                         memcpy(ptr,&iphead,sizeof(IP_HEADER));
  206.                         ptr += sizeof(IP_HEADER);
  207.                         memcpy(ptr,&udphead,sizeof(UDP_HEADER));
  208.                         ptr += sizeof(UDP_HEADER);
  209.                         memcpy(ptr,buf,strlen(buf));
  210.                         usleep(2000000);
  211.                         int len=-1;
  212.                         if ((len = sendto(sockfd,msg_tx,PACKET_LEN,0,(struct sockaddr *)&client,add_len)) < 0)
  213.                         {
  214.                                 perror("sendto");
  215.                         }
  216.                 }
  217.                 printf("\n=====================================================================\n");
  218.                
  219.         }
  220.         free(pudp);
  221.         pip = NULL;
  222.         free(pip);
  223.         pudp = NULL;
  224.        
  225.         close(sockfd);
  226.        
  227. }


  228. //客户端
  229. #include "header.h"
  230. int main()
  231. {
  232.         int sockfd;
  233.         struct sockaddr_in server,client;
  234.         struct hostent *ht;
  235.         IP_HEADER *iphead = (IP_HEADER*)malloc(sizeof(IP_HEADER));
  236.         UDP_HEADER *udphead = (UDP_HEADER*)malloc(sizeof(UDP_HEADER));
  237.         PSD_HEADER *psdhead = (PSD_HEADER*)malloc(sizeof(PSD_HEADER));
  238.         struct in_addr my_addr;

  239.     struct in_addr serv_addr;

  240.         char hostname[20],qstr[] = "quit";
  241.         char msg_tx[MSG_LEN];
  242.         char msg_rx[MSG_LEN],buf[PACKET_LEN];                /*message and buffer to send */
  243.         int on=1;
  244.         int add_len = sizeof(struct sockaddr);
  245.         //pthread_t tid;
  246.        
  247.         printf("Enter the server's IP:\n");
  248.         scanf("%s",hostname);
  249.        
  250.         //create a socket for communicatting
  251.         if((sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_UDP)) == -1)
  252.         {
  253.                 perror("socket");
  254.                 exit(1);
  255.         }
  256.        
  257.         //set the socket option
  258.         if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,&on, sizeof(on)) < 0)
  259.         {
  260.                 printf("setsockopt error!");
  261.                 close(sockfd);
  262.                 exit(1);
  263.         }
  264.        
  265.         //get host form IP address
  266.         if((ht = gethostbyname(hostname)) == NULL)
  267.         {
  268.                 perror("gethostbyname");
  269.                 exit(1);
  270.         }
  271.         printf("socket success...");
  272.        
  273.         //copy IP of server to server's struct
  274.         memcpy(&server.sin_addr,ht->h_addr,ht->h_length);        

  275.         server.sin_family = AF_INET;

  276.         server.sin_port=htons(SERVER_PORT);
  277.         bzero(&(server.sin_addr),8);

  278.     memset(buf, 0x00, MSG_LEN);


  279.         //ip header

  280.         iphead->h_lenver = (4<<4|sizeof(IP_HEADER)/sizeof(unsigned long));

  281.     iphead->tos = 0;

  282.     iphead->id  = htons((unsigned short)rand());

  283.     iphead->off = 0;

  284.     iphead->ttl = MAX_ROUTE_HOP;

  285.     iphead->proto  = IPPROTO_UDP;

  286.     iphead->sum = 0;

  287.     iphead->srcIP = server.sin_addr;                //测试用的环路地址127.0.0.1

  288.     iphead->dstIP = server.sin_addr;
  289.    
  290.     //udp header
  291.     udphead->uh_sport = htons(CLIENT_PORT);
  292.     udphead->uh_dport = htons(SERVER_PORT);
  293.     udphead->uh_sum = 0;
  294.    
  295.     //psd header
  296.     psdhead->saddr = iphead->srcIP;
  297.     psdhead->daddr = iphead->dstIP;
  298.     psdhead->mbz = 0;
  299.     psdhead->proto = iphead->proto;
  300.     //psdhead->len = udphead->uh_len;
  301.    
  302.     //send message
  303.     printf("\nYou can talk now!\n");
  304.    
  305.     int msg_tx_num = 0;
  306.     int msg_rx_num = 0;
  307.     printf("input msg_tx\n");
  308.             scanf("%s",msg_tx);
  309.         while(1)
  310.         {
  311.                 char *ptr = buf;
  312.                 printf("input msg_tx\n");
  313.             scanf("%s",msg_tx);
  314.                 memset(buf, 0x00, sizeof(buf));
  315.                 iphead->t_len = htons(sizeof(IP_HEADER)+sizeof(UDP_HEADER)+strlen(msg_tx));
  316.                 udphead->uh_len = htons(sizeof(UDP_HEADER)+strlen(msg_tx));
  317.                 psdhead->len = udphead->uh_len;

  318.                 //form a packet to send
  319.                 memcpy(ptr,iphead,sizeof(IP_HEADER));
  320.                 ptr += sizeof(IP_HEADER);
  321.                 memcpy(ptr,udphead,sizeof(UDP_HEADER));
  322.                 ptr += sizeof(UDP_HEADER);
  323.                 memcpy(ptr,msg_tx,strlen(msg_tx));
  324.                 int len=-1;
  325.                 if ((len =sendto(sockfd,buf,PACKET_LEN,0,(struct sockaddr *)(&server),sizeof(struct sockaddr))) < 0)
  326.                 {
  327.                         perror("sendto");
  328.                 }
  329.                 else
  330.                 {
  331.                         printf("\n发送:%d,%s\n",msg_tx_num++,msg_tx);
  332.                         /*打印消息,以便调试*/
  333.                         IP_HEADER *pip;
  334.                         UDP_HEADER *pudp;
  335.                         pip = (IP_HEADER*)buf;
  336.                         pudp = (UDP_HEADER*)(buf+20);
  337.                         printf("\n协议:%d,校验和:%d,源地址:%ld,目的地址:%ld\n",
  338.                                         pip->proto,pip->sum,(long int)(pip->srcIP.s_addr),(long int)(pip->dstIP.s_addr));
  339.                         printf("源端口:%d,目的端口:%d,长度:%d\n",
  340.                                         pudp->uh_sport,pudp->uh_dport,pudp->uh_len);
  341.                 }
  342.                
  343.                 memset(buf,0x00,sizeof(buf));
  344.                 memset(msg_rx,0x00,sizeof(msg_rx));
  345.                 usleep(2000000);
  346.                 len = -1;
  347.                 if((len = recvfrom(sockfd,msg_rx,PACKET_LEN,0,(struct sockaddr*)(&server),&add_len)) > 0)
  348.                 {
  349.                         char tmp[MSG_LEN];
  350.                         memcpy(tmp,buf+sizeof(IP_HEADER)+sizeof(UDP_HEADER),MSG_LEN);
  351.                         printf("%s",tmp);
  352.                 }
  353.                 printf("\n=====================================================================\n");
  354.         }
  355. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2010-08-31 22:32 |只看该作者
(gdb) p client
$3 = {sin_family = 2, sin_port = 0, sin_addr = {s_addr = 57701834},
  sin_zero = "\000\000\000\000\000\000\000"}

上边是单步调试的结果,sin_port = 0,这是为什么?

论坛徽章:
1
CU十二周年纪念徽章
日期:2013-10-24 15:41:34
3 [报告]
发表于 2010-08-31 22:33 |只看该作者
代码好长啊!

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
4 [报告]
发表于 2010-09-01 09:46 |只看该作者
服务端的add_len在recvfrom之前没有初始化

论坛徽章:
0
5 [报告]
发表于 2010-09-01 09:52 |只看该作者
最近怎么问问题的代码越贴越长……

论坛徽章:
0
6 [报告]
发表于 2010-09-01 10:32 |只看该作者
回复 3# ecjtubaowp


    我只是想让问题能看的更明白点,呵呵!

论坛徽章:
0
7 [报告]
发表于 2010-09-01 10:36 |只看该作者
回复 4# hellioncu


    在第114行初始化的,还是没有找出原因。

    用原始套接字的时候,我给udp包头的原地址和目的地址都赋值为4567了,但是通信的时候,使用的端口是不是4567呢?
   
    我用了另外一个程序查看,貌似不是这样的,通信的端口和我在UDP 包头里边自己家的UDP端口号不是一样的。

    为什么呢?怎么样设置UDP的端口号?

论坛徽章:
0
8 [报告]
发表于 2010-09-01 10:36 |只看该作者
回复 5# daybreakcx


    第一次贴代码,下次我尽量精简!

论坛徽章:
0
9 [报告]
发表于 2010-09-01 12:51 |只看该作者
回复 7# whyliyi

    每次recvfrom 都把client清0, add_len设为 sizeof(client)。

论坛徽章:
0
10 [报告]
发表于 2010-09-01 19:05 |只看该作者
回复 9# zzyong08


    试了。不行,我想 了一下,估计应该是我在原始套接字中设置了UDP中的原端口为4567,而实际通信的过程中,用的并不是4567这个端口,因此在接收数据的时候出现问题!
怎么样设置客户端的通信端口呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP