免费注册 查看新帖 |

Chinaunix

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

一个头痛的问题! UDP网络编程的sendto和recvfrom!!请求大家帮助 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-06-18 19:01 |只看该作者 |倒序浏览
本帖最后由 guaguaguaguaxi 于 2010-06-19 11:06 编辑

首先我想实现的是兼容IPV4,IPV6的网络程序,所以我的socket都是用getaddrinfo创建的.
我遇到的问题是:
我在TCP服务器端的accept之后(即客户端连接之后)用getnameinfo函数可以获得客户端的IP以及PORT,然后用这个IP和端口来用sendto发送消息到客户端.
一般的UDP编程都是客户端先发送,然后服务器端再接收,接收到之后recvfrom后面两个参数已经有了客户端的IP和端口消息,服务器端利用recvfrom的消息再来sendto发送消息到客户端.
而我要是实现的是利用getnameinfo函数获得的IP和端口消息(两个字符串类型),我的部分代码如下所示:

TCP服务器端:  (UDP的服务器端也在同个程序中),TCP和UDP用的端口不一样
  1. newfd=accept(s[i],(struct sockaddr *)&from, &fromlen);
  2. if(newfd<0)   continue;

  3. ret=getnameinfo((struct sockaddr *)&from, fromlen, hostddr,sizeof(hostddr), cliddr,sizeof( cliddr), NI_NUMERICHOST | NI_NUMERICSERV);
  4. printf("trying %s port %s\n",hostddr,cliddr); // 可以得到客户端的IP和端口消息
  5.                                                                        
  6. udp_addr(hostddr,cliddr,&peer_addr,&peer_addr_len); // 通过udp_addr函数把IP和端口消息写入peer_addr
  7. len=sendto(udpfd, buffer, strlen(buffer), 0,peer_addr,peer_addr_len);// 发送简单字符串,例如"xigua"
  8. printf("sendto len=%d\n",len);//长度打印为5
复制代码
其中udp_addr函数为:
  1. void udp_addr(const char *host, const char *serv, struct sockaddr **saptr, socklen_t *lenp)
  2. {
  3.         int sockfd, n;
  4.         struct addrinfo        hints, *res, *ressave;

  5.         bzero(&hints, sizeof(struct addrinfo));
  6.         hints.ai_family = AF_UNSPEC;
  7.         hints.ai_socktype = SOCK_DGRAM;

  8.         if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0)
  9.                 printf("udp_client error for %s, %s: %s",host, serv, gai_strerror(n));

  10.         *saptr =(struct sockaddr *) malloc (res->ai_addrlen);
  11.         memcpy((void*)*saptr, res->ai_addr, res->ai_addrlen);
  12.         *lenp = res->ai_addrlen;

  13.        
  14. }
复制代码
TCP客户端:  (UDP的客户端也在同个程序中)
  1. int udp_client(const char *host, const char *serv)
  2. {
  3.         int sockfd, n,error;
  4.         struct addrinfo        hints, *res, *ressave;
  5.          char hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];

  6.         bzero(&hints, sizeof(struct addrinfo));
  7.         hints.ai_family = AF_UNSPEC;
  8.         hints.ai_socktype = SOCK_DGRAM;

  9.         if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0)
  10.                 printf("udp_client error for %s, %s: %s",host, serv, gai_strerror(n));

  11.         ressave = res;
  12.         do {
  13.          sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  14.                 if (sockfd >= 0)
  15.                         break;                               
  16.         } while ( (res = res->ai_next) != NULL);

  17.         if (res == NULL)                                       
  18.                 printf("udp_client error for %s, %s", host, serv);

  19.         freeaddrinfo(ressave);
  20.         return(sockfd);
  21. }


  22. int main(int argc, char *argv[])
  23. {
  24.          int sockfd,udpfd, len;
  25.          char buf[1024] ;
  26.          struct sockaddr_storage from;
  27.          socklen_t fromlen;

  28.          if (argc == 4) {
  29.                 sockfd =tcp_connect (argv[1], argv[2]);         //TCP客户端,IP和UDP的一样,端口与TCP服务器端的一样
  30.                 udpfd= udp_client (argv[1], argv[3]);  //UDP客户端,端口与UDP服务器端的一样

  31.          }
  32.          
  33.         while(1)
  34.         {
  35.             memset(buf,0,sizeof(buf));
  36.             fromlen= sizeof(struct sockaddr_storage);
  37.            len=recvfrom (udpfd, buf,sizeof(buf),0,(struct sockaddr *)&from, &fromlen);  
  38.            if(len <= 0){
  39.                perror("recv");
  40.                continue;
  41.         }
  42.            buf[len]=0;
  43.            fprintf(stdout,"server > %s\n",buf);         
  44.         }
  45.         return 0;
  46. }
复制代码
如上面的程序,服务器sendto函数之后打印发送长度len为5,好象是发送出去了,但是客户端这边却什么也没收到,recvfrom阻塞在那里.
大家帮我看看怎么解决,不甚感激!!!!!!!!

我突然想到,accept之后用getnameinfo函数获得的客户端的IP以及PORT是TCP客户端的,不是UDP客户端的,那又应该怎么办呢?急需大家的帮助,谢谢.

论坛徽章:
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
2 [报告]
发表于 2010-06-18 21:54 |只看该作者
用code方式贴代码,不然看着头晕

论坛徽章:
0
3 [报告]
发表于 2010-06-19 09:50 |只看该作者
回复 2# hellioncu

不好意思,以前不知道有那个方式,谢谢你的提醒.

论坛徽章:
0
4 [报告]
发表于 2010-06-19 11:46 |只看该作者
还没仔细看代码,不过UDP方式的编程,是不会用到accept的吧?
套路上是 TCP的server要设置listen然后等待client connect,然后accept得到描述符。
UDP是直接recvfrom收过来,地址在包里的呀。

论坛徽章:
0
5 [报告]
发表于 2010-06-19 12:03 |只看该作者
本帖最后由 guaguaguaguaxi 于 2010-06-19 12:08 编辑

一般的UDP网络编程是需要:客户端主动建立到服务器的连接,然后服务器才能在这个连接上发送,即
客户端先sendto,然后服务器端再接收,接收到之后recvfrom后面两个参数已经有了客户端的IP和端口消息,服务器端利用这些客户端消息再来sendto发送消息到客户端.
而我的情况是事先知道客户端的IP和端口,在服务器端直接sendto,那此时的客户端程序应该怎么写,可以直接recvfrom吗??需要sendto吗??????

请各位高手帮帮忙,谢谢.

论坛徽章:
0
6 [报告]
发表于 2010-06-19 12:07 |只看该作者
回复 4# 聪聪知不道


    我知道UDP是用不到accept的,可我的问题是先用TCP创建个连接,我就知道客户端的IP和PORT,再用UDP来直接发送.

论坛徽章:
0
7 [报告]
发表于 2010-06-19 12:25 |只看该作者
本帖最后由 memoryboxes 于 2010-06-19 12:26 编辑

我也觉得楼上说得对,没有看到你TCP客户端的实现方式,但是读了楼主的源码之后,过程好像是:TCP客户端发送消息给服务端,服务端调用getnameinfo()得到的是TCP客户端的IP和PORT,向这个地址发送消息,而在udp端绑定的地址是当然不可能接收到这个消息的。另外,也没有看到udp客户端发送消息啊。
如果要用udp通信,服务器端是recvfrom收过来,然后发送就可以。
另外,sendto()和recvfrom()都可以用于TCP,但是通常没有这样做的理由。

建议楼主先单独实现udp和tcp的通信,然后用并发分别处理这两个问题,我觉得把TCP和UDP的通讯实现放在一个锅里有点乱。

论坛徽章:
0
8 [报告]
发表于 2010-06-19 12:40 |只看该作者
其实我是不太明白你为什么要这样做。你用TCP的方式去connect和用UDP的方式sendto,不是都是一次调用吗?未必搞这么复杂。

论坛徽章:
0
9 [报告]
发表于 2010-06-19 12:42 |只看该作者
事先知道客户端的IP和端口,在服务器端直接sendto,那此时的客户端程序应该怎么写,可以直接recvfrom吗??需要sendto吗?
可以的,知道客户临时端口号的任何进程都可以往客户发送数据包,而且这些数据报会与正常的服务器应答混杂。所以一般udp通信需要得到数据报发送者的IP和端口号进行验证。但比如你向192.168.1.2:8000 发送一个udp数据报的话能是recvfrom()到的,但前提是你得bind()一下。而我们平时的sendto()调用时是内核为我们选择一个临时端口的。

是先用TCP创建个连接,我就知道客户端的IP和PORT,再用UDP来直接发送.
用TCP创建的连接端口号与UDP端的recvfrom()的端口号是不同的。
正常的udp通信程序是:udp客户端sendto()--此时你没有自己绑定的话内核给你选择端口号,服务端recvfrom(),再sendto(),客户端再recvfrom(),最后close()。

就是用tcp连接得到的地址和端口号如果不做特殊处理的话是不能用于udp通信的。

论坛徽章:
0
10 [报告]
发表于 2010-06-19 12:48 |只看该作者
另外,楼主你想验证的话,只要写个udp客户端通信程序,用sendip之类的发包工具构造一个包发送一下验证看看就可以了。结合netstat命令会看得更明白。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP