Linux网络编程 之 UDP 广播 .

转载 2015年07月09日 11:20:35

在网上搜了很多资料 ,其中周立发的博客对我的学习参考作用最大,谢谢前辈。

这个倒让我花的时间最多了,主要一直脑残的在自己的虚拟机上调试不成功,认为只要开几个终端就可以当作服务器了,这种想法是错误的。因为ip地址会被占用的,所以后来我和同事测试一下,就OK了。

这个广播代码逻辑其实挺有用的,可以用来寻找所在局域网内设备

逻辑就是:客户端一直发广播,当服务器收到这个广播,则向客户端回个确认,这样客户端收到确认后就知道有所要的服务器了

  直接上代码吧,一个很简单udp 广播通信的例子,分别为服务器端和客户端的代码。


1、服务器代码 (bcast_server.c)

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /********************************************************************* 
  2.  * Filename: bcast_server.c 
  3.  * Description: 广播服务器端代码 
  4.  * Author: Eric(wongpz@foxmail.com) 
  5.  * Date: 2012-9-14 
  6.  ********************************************************************/  
  7. #include <stdio.h>  
  8. #include <string.h>  
  9. #include <sys/types.h>  
  10. #include <sys/socket.h>  
  11. #include <fcntl.h>  
  12. #include <linux/in.h>  
  13. #include <stdlib.h>  
  14.   
  15. #define IP_FOUND "IP_FOUND"  
  16. #define IP_FOUND_ACK "IP_FOUND_ACK"  
  17. #define PORT 9999  
  18.   
  19. int main(int argc, char*argv[])  
  20. {  
  21.     int ret = -1;  
  22.     int sock;  
  23.     struct sockaddr_in server_addr; //服务器端地址  
  24.     struct sockaddr_in from_addr; //客户端地址  
  25.     int from_len = sizeof(struct sockaddr_in);  
  26.     int count = -1;  
  27.     fd_set readfd; //读文件描述符集合  
  28.     char buffer[1024];  
  29.     struct timeval timeout;  
  30.     timeout.tv_sec = 2;  
  31.     timeout.tv_usec = 0;  
  32.   
  33.     sock = socket(AF_INET, SOCK_DGRAM, 0); //建立数据报套接字  
  34.     if (sock < 0)  
  35.     {  
  36.         perror("sock error");  
  37.         return -1;  
  38.     }  
  39.   
  40.     memset((void*) &server_addr, 0sizeof(struct sockaddr_in));  
  41.     server_addr.sin_family = AF_INET;  
  42.     server_addr.sin_addr.s_addr = htons(INADDR_ANY );  
  43.     server_addr.sin_port = htons(PORT);  
  44.   
  45.     //将地址结构绑定到套接字上  
  46.     ret = bind(sock, (struct sockaddr*) &server_addr, sizeof(server_addr));  
  47.     if (ret < 0)  
  48.     {  
  49.         perror("bind error");  
  50.         return -1;  
  51.     }  
  52.   
  53.     /** 
  54.      * 循环等待客户端 
  55.      */  
  56.     while (1)  
  57.     {  
  58.         timeout.tv_sec = 100;  
  59.         timeout.tv_usec = 0;  
  60.   
  61.         //文件描述符集合清0  
  62.         FD_ZERO(&readfd);  
  63.   
  64.         //将套接字描述符加入到文件描述符集合  
  65.         FD_SET(sock, &readfd);  
  66.   
  67.         //select侦听是否有数据到来  
  68.         ret = select(sock + 1, &readfd, NULLNULL, &timeout); //侦听是否可读  
  69.         switch (ret)  
  70.         {  
  71.         case -1//发生错误  
  72.             perror("select error:");  
  73.             break;  
  74.         case 0//超时  
  75.             printf("select timeout\n");  
  76.             break;  
  77.         default:  
  78.             if (FD_ISSET(sock,&readfd))  
  79.             {  
  80.                 count = recvfrom(sock, buffer, 10240,  
  81.                         (struct sockaddr*)&from_addr, &from_len); //接收客户端发送的数据  
  82.   
  83.                 //from_addr保存客户端的地址结构  
  84.                 if (strstr(buffer, IP_FOUND))  
  85.                 {  
  86.                     //响应客户端请求  
  87.                     //打印客户端的IP地址和端口号  
  88.                     printf("\nClient connection information:\n\t IP: %s, Port: %d\n",  
  89.                             (charchar *)inet_ntoa(from_addr.sin_addr),  
  90.                             ntohs(from_addr.sin_port));  
  91.   
  92.                     //将数据发送给客户端  
  93.                     memcpy(buffer, IP_FOUND_ACK, strlen(IP_FOUND_ACK) + 1);  
  94.                     count = sendto(sock, buffer, strlen(buffer), 0,  
  95.                             (struct sockaddr*) &from_addr, from_len);  
  96.                 }  
  97.             }  
  98.             break;  
  99.         }  
  100.     }  
  101.     return 0;  
  102. }  


2、客户端代码(bcast_clinet.c)

 

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /********************************************************************* 
  2.  * Filename: bcast_client.c 
  3.  * Description:广播客户端代码 
  4.  * Author: Eric(wongpz@foxmail.com) 
  5.  * Date: 2012-9-14 
  6.  ********************************************************************/  
  7. #include<stdio.h>  
  8. #include<stdlib.h>  
  9. #include<unistd.h>  
  10. #include<string.h>  
  11. #include<sys/socket.h>  
  12. #include<arpa/inet.h>  
  13. #include<netinet/in.h>  
  14. #include<sys/types.h>  
  15. #include<netdb.h>  
  16. #include <sys/ioctl.h>  
  17. #include <net/if.h>  
  18.   
  19. #define IP_FOUND "IP_FOUND"  
  20. #define IP_FOUND_ACK "IP_FOUND_ACK"  
  21. #define IFNAME "eth0"  
  22. #define MCAST_PORT 9999  
  23.   
  24. int main(int argc, char*argv[])  
  25. {  
  26.     int ret = -1;  
  27.     int sock = -1;  
  28.     int j = -1;  
  29.     int so_broadcast = 1;  
  30.     struct ifreq *ifr;  
  31.     struct ifconf ifc;  
  32.     struct sockaddr_in broadcast_addr; //广播地址  
  33.     struct sockaddr_in from_addr; //服务端地址  
  34.     int from_len = sizeof(from_addr);  
  35.     int count = -1;  
  36.     fd_set readfd; //读文件描述符集合  
  37.     char buffer[1024];  
  38.     struct timeval timeout;  
  39.     timeout.tv_sec = 2//超时时间为2秒  
  40.     timeout.tv_usec = 0;  
  41.   
  42.     //建立数据报套接字  
  43.     sock = socket(AF_INET, SOCK_DGRAM, 0);  
  44.     if (sock < 0)  
  45.     {  
  46.         perror("create socket failed:");  
  47.         return -1;  
  48.     }  
  49.   
  50.     // 获取所有套接字接口  
  51.     ifc.ifc_len = sizeof(buffer);  
  52.     ifc.ifc_buf = buffer;  
  53.     if (ioctl(sock, SIOCGIFCONF, (charchar *) &ifc) < 0)  
  54.     {  
  55.         perror("ioctl-conf:");  
  56.         return -1;  
  57.     }  
  58.     ifr = ifc.ifc_req;  
  59.     for (j = ifc.ifc_len / sizeof(struct ifreq); --j >= 0; ifr++)  
  60.     {  
  61.         if (!strcmp(ifr->ifr_name, "eth0"))  
  62.         {  
  63.             if (ioctl(sock, SIOCGIFFLAGS, (charchar *) ifr) < 0)  
  64.             {  
  65.                 perror("ioctl-get flag failed:");  
  66.             }  
  67.             break;  
  68.         }  
  69.     }  
  70.   
  71.     //将使用的网络接口名字复制到ifr.ifr_name中,由于不同的网卡接口的广播地址是不一样的,因此指定网卡接口  
  72.     //strncpy(ifr.ifr_name, IFNAME, strlen(IFNAME));  
  73.     //发送命令,获得网络接口的广播地址  
  74.     if (ioctl(sock, SIOCGIFBRDADDR, ifr) == -1)  
  75.     {  
  76.         perror("ioctl error");  
  77.         return -1;  
  78.     }  
  79.     //将获得的广播地址复制到broadcast_addr  
  80.     memcpy(&broadcast_addr, (charchar *)&ifr->ifr_broadaddr, sizeof(struct sockaddr_in));  
  81.     //设置广播端口号  
  82.     printf("\nBroadcast-IP: %s\n", inet_ntoa(broadcast_addr.sin_addr));  
  83.     broadcast_addr.sin_family = AF_INET;  
  84.     broadcast_addr.sin_port = htons(MCAST_PORT);  
  85.   
  86.     //默认的套接字描述符sock是不支持广播,必须设置套接字描述符以支持广播  
  87.     ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so_broadcast,  
  88.             sizeof(so_broadcast));  
  89.   
  90.     //发送多次广播,看网络上是否有服务器存在  
  91.     int times = 10;  
  92.     int i = 0;  
  93.     for (i = 0; i < times; i++)  
  94.     {  
  95.         //一共发送10次广播,每次等待2秒是否有回应  
  96.         //广播发送服务器地址请求  
  97.         timeout.tv_sec = 2;  //超时时间为2秒  
  98.         timeout.tv_usec = 0;  
  99.         ret = sendto(sock, IP_FOUND, strlen(IP_FOUND), 0,  
  100.                 (struct sockaddr*) &broadcast_addr, sizeof(broadcast_addr));  
  101.         if (ret < 0)  
  102.         {  
  103.             continue;  
  104.         }  
  105.   
  106.         //文件描述符清0  
  107.         FD_ZERO(&readfd);  
  108.         //将套接字文件描述符加入到文件描述符集合中  
  109.         FD_SET(sock, &readfd);  
  110.         //select侦听是否有数据到来  
  111.         ret = select(sock + 1, &readfd, NULLNULL, &timeout);  
  112.         switch (ret)  
  113.         {  
  114.         case -1:  
  115.             break;  
  116.         case 0:  
  117.             perror("select timeout\n");  
  118.             break;  
  119.         default:  
  120.             //接收到数据  
  121.             if (FD_ISSET(sock,&readfd))  
  122.             {  
  123.                 count = recvfrom(sock, buffer, 10240,  
  124.                         (struct sockaddr*) &from_addr, &from_len); //from_addr为服务器端地址  
  125.                 printf("\trecvmsg is %s\n", buffer);  
  126.                 if (strstr(buffer, IP_FOUND_ACK))  
  127.                 {  
  128.                     printf("\tfound server IP is %s, Port is %d\n",  
  129.                             inet_ntoa(from_addr.sin_addr),  
  130.                             htons(from_addr.sin_port));  
  131.                 }  
  132.                 return -1;  
  133.   
  134.             }  
  135.             break;  
  136.   
  137.         }  
  138.     }  
  139.     return 0;  
  140. }  

最后它的Makefile:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. OBJS_SERVER = bcast_server.o  
  2. OBJS_CLIENT = bcast_client.o  
  3. LIBS_SERVER =   
  4. LIBS_CLIENT =   
  5.   
  6. CFLAGS = -c  
  7. CC = gcc  
  8.   
  9. PROS = bcast_client bcast_server  
  10.   
  11. all: $(PROS)  
  12.   
  13. .c.o:  
  14.     $(CC) $(CFLAGS) $<  
  15.   
  16. bcast_client: $(OBJS_CLIENT)  
  17.     $(CC) -o $@ $^ $(LIBS_SERVER)  
  18.   
  19. bcast_server: $(OBJS_SERVER)  
  20.     $(CC) -o $@ $^ $(LIBS_CLIENT)  
  21.   
  22. clean:  
  23.     rm -rf $(PROS) $(OBJS_CLIENT) $(OBJS_SERVER)  

运行效果如图:



linux网络编程源代码下载:http://download.csdn.net/detail/yanyuanfen2011/6595113


如有问题欢迎留言交流!

Linux网络编程 之 UDP 广播

最近一直在做linux的网络,现在作个总结,陆续贴出来。 在网上搜了很多资料 ,其中周立发的博客对我的学习参考作用最大,谢谢前辈。 这个倒让我花的时间最多了,主要一直脑残的在自己的虚拟机上调试不...
  • yanyuanfen2011
  • yanyuanfen2011
  • 2013年11月22日 18:24
  • 4442

linux下网络编程3:UDP广播传输文件

问题描述: 采用UDP协议广播传输文件。所谓UDP协议是面向无连接的,不可靠的,工作于传输层的一种协议。这里补充讲解下ISO七层网络模型。 常见的ISO七层网络模型基本可以由下图进行概括说明: 对于...
  • ljp1919
  • ljp1919
  • 2015年08月14日 18:31
  • 807

Linux网络编程——UDP服务器和广播/组播

学习笔记,小白可以相互学习,大佬看到能告诉咱理解不对的地方就好了。
  • wp1027322856
  • wp1027322856
  • 2017年08月27日 17:15
  • 100

Linux网络编程之基于UDP实现可靠的文件传输示例

了解网络传输协议的人都知道,采用TCP实现文件传输很简单。相对于TCP,由于UDP是面向无连接、不可靠的传输协议,所以我们需要考虑丢包和后发先至(包的顺序)的问题,所以我们想要实现UDP传输文件,则需...
  • eerstar
  • eerstar
  • 2015年08月18日 22:38
  • 746

linux UDP 局域网内广播通信服务器端和客户端

在调试局域网内通过UDP协议获取其他设备IP地址时,服务器使用UDP 广播后, 客户端设备无响应. 先研究一下正常情况下, UDP广播通信方法. 参考了网络上一写资料. 代码整理如下: 服务器端...
  • yishengzhiai005
  • yishengzhiai005
  • 2014年08月29日 17:09
  • 975

Linux网络编程 之 UDP 广播 .

在网上搜了很多资料 ,其中周立发的博客对我的学习参考作用最大,谢谢前辈。 这个倒让我花的时间最多了,主要一直脑残的在自己的虚拟机上调试不成功,认为只要开几个终端就可以当作服务器了,这种想法是错误...
  • dxpqxb
  • dxpqxb
  • 2014年08月06日 16:37
  • 1365

C#实现局域网UDP广播------C#网络编程杂记[1]

 学校开课C#网络编程,今天就研究了一下"C#实现局域网UDP广播,这一块设置到局域网"飞鸽"类似的通讯软件编程,需要用到的主要命名空间是:System.Net和System.Net.Scoket: ...
  • tt03030576
  • tt03030576
  • 2008年03月14日 10:54
  • 9505

Qt实现UDP广播简例

Qt的UDP广播简例
  • HackerTom
  • HackerTom
  • 2017年06月22日 15:43
  • 377

linux 多网卡发送udp广播

一、客户端代码 #include #include #include #include #include #include #include void  *ThreadProc(vo...
  • huangkaiyue1
  • huangkaiyue1
  • 2017年04月03日 15:28
  • 678

Linux下的udp广播与接收程序 包含序列号

[代码] udp_send.c #include #include #include #include #include #include #include #include #include #i...
  • huaxi1902
  • huaxi1902
  • 2013年01月13日 21:06
  • 1170
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux网络编程 之 UDP 广播 .
举报原因:
原因补充:

(最多只允许输入30个字)