tcp/udp搜索局域网主机的基本原理_广播域和冲突域的概念

tcp/udp搜索局域网主机的基本原理_广播域和冲突域的概念调试过程中很多坑,特别在windows下很多设置要特殊处理,如头文件winsock2要写在windows前面,设置参数不可以用(xxxx|xxxx)一次性设置,需要分开两次等等,还有其他设置项出错导致发送失败

tcp/udp搜索局域网主机的基本原理_广播域和冲突域的概念"

1.简介

        很多有这样需求的上位机都会具有一键搜索局域网内设备,各家用的方法都各不相同。

        这样做非常方便用户使用,用户不再需要在设备端确定设备ip,在上位机上在输入,然后连接。一键就可以发现并选择对应的设备,这种功能一听就很有吸引力,以下就着手实现该功能。

2.原理

        原理很简单,找到对方ip,然后对协议,协议对上后即可确认对方设备为自己需要的。

        那么难点就在于找到ip,以下列举几种方法:

        ① ping网段下所有的ip,ping通的地址再发送私有协议

        ② 广播自身地址,设备收到后主动连接

        ③ 设立服务器,设备主动连接服务器

3.实现

        基于第二种方法,以下C语言实现相关功能

        首先肯定是socket初始化并配置ip端口了

        socket= socket(PF_INET, SOCK_DGRAM, 0));

        对于发送端,我们还需要配置socket的属性是广播,这样才能发送广播包

        int optval = 1;

        setsockopt(socket, SOL_SOCKET, SO_BROADCAST , &optval, sizeof(optval));

         然后设置ip及端口

        struct sockaddr_in recvAddr;

        memset(&recvAddr, 0, sizeof(struct sockaddr_in));

        recvAddr.sin_family = AF_INET;

        recvAddr.sin_port = htons(port);

        recvAddr.sin_addr.s_addr = INADDR_ANY;

         发送端就完成初始化操作了。但是对于接收端,还需要绑定端口,不然无法接收信息

bind(socket, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr));

        最后发送端使用发送函数发送需要的内容

sendto(socket, sendbuf, len, 0, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) 

        接收端则接收

recvfrom(socket, recvbuf, sizeof(recvbuf), 0,(struct sockaddr *)&recvAddr, &addrLen);

         这样接收端就得到对方地址了,后面就可以根据自己需求做相应的操作。

下面给出发送端程序

int broadcast_server_init(struct broadcast_handle *bse, broadcast_mode mode, char *ip, uint16_t port, long timeout) { if(!bse) return -1; if((bse->fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1){ strcpy(bse->msg,"socket fail"); return -1; } int optval = 1;//这个值一定要设置,否则可能导致sendto()失败 if(setsockopt(bse->fd, SOL_SOCKET, SO_BROADCAST , (char *)&optval, sizeof(optval)) == -1) //windows下需要分开设置 { strcpy(bse->msg,"setsockopt fail 1"); return -1; } if(setsockopt(bse->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) { strcpy(bse->msg,"setsockopt fail 2"); return -1; } struct timeval tv = {1,0}; //first means sec, second means usec setsockopt(bse->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); memset(&bse->thisAddr, 0, sizeof(struct sockaddr_in)); bse->thisAddr.sin_family = AF_INET; if(!ip) bse->thisAddr.sin_addr.s_addr = inet_addr("255.255.255.255"); else bse->thisAddr.sin_addr.s_addr = inet_addr(ip); bse->thisAddr.sin_port = htons(port); return 0; } int broadcast_server_run(struct broadcast_handle *bse) { if(!bse || (bse->fd==-1)) return -1; int ret,len; char recvbuf[MAX_BUFFER_LEN],sendbuf[MAX_BUFFER_LEN]; struct sockaddr_in recvAddr; int addrLen = sizeof(struct sockaddr_in); if((ret = sendto(bse->fd, sendbuf, len, 0, (struct sockaddr *)&bse->thisAddr, sizeof(struct sockaddr))) == -1) { sprintf(bse->msg, "sendto fail, ret=%d\n", ret); return -1; } if((ret = recvfrom(bse->fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&recvAddr, &addrLen)) > 0) { recvbuf[ret] = '\0'; if(authentication(bse,recvbuf) == -1) continue; fun_avltree_unit* info = malloc(sizeof(fun_avltree_unit)); if(!info) { strcpy(bse->msg,"malloc list fail"); return -1; } strncpy(info->remote_ip,(char *)inet_ntoa(recvAddr.sin_addr),sizeof(info->remote_ip)); info->remote_port = htons(recvAddr.sin_port); info->key = info->remote_ip; if(tree_add_remote_info(bse,info) != 0) { strcpy(bse->msg,"insert info fail"); free(info); } #ifdef BROADCAST_DEBUG printf("IP:%s\n", info->remote_ip); printf("Port:%d\n", info->remote_port); printf("receive a broadCast messgse:%s\n", recvbuf); #endif } }

接收端程序:

int broadcast_client_init(struct broadcast_handle *bcl, broadcast_mode mode, char *ip, uint16_t port, long timeout) { if(!bcl) return -1; bcl->fd = socket(AF_INET, SOCK_DGRAM, 0); if(bcl->fd == -1) { strcpy(bcl->msg,"socket fail"); return -1; } int set = 1; if(setsockopt(bcl->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&set, sizeof(set)) == -1) //set char* to adapter windows api { strcpy(bcl->msg,"setsockopt fail"); return -1; } struct timeval tv = {timeout,0}; //first means sec, second means usec if(timeout>=0) setsockopt(bcl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); struct sockaddr_in recvAddr; memset(&recvAddr, 0, sizeof(struct sockaddr_in)); recvAddr.sin_family = AF_INET; recvAddr.sin_port = htons(port); if(ip==NULL) recvAddr.sin_addr.s_addr = INADDR_ANY; else recvAddr.sin_addr.s_addr = inet_addr(ip); if(bind(bcl->fd, (struct sockaddr *)&recvAddr, sizeof(struct sockaddr)) == -1){ strcpy(bcl->msg,"bind fail"); return -1; } return 0; } int broadcast_client_run(struct broadcast_handle *bcl) { int ret; char recvbuf[MAX_BUFFER_LEN]; struct sockaddr_in recvAddr; int addrLen = sizeof(struct sockaddr_in); time_t startTime = get_timestamp(); do { #ifndef _WIN32 if((ret = recvfrom(bcl->fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&recvAddr, (socklen_t*)&addrLen)) > 0) #else if((ret = recvfrom(bcl->fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&recvAddr, &addrLen)) > 0) #endif { recvbuf[ret] = '\0'; if(sendto(bcl->fd, recvbuf, ret, 0, (struct sockaddr *)&recvAddr, addrLen) < 0) { sprintf(bcl->msg,"sendto fail"); return -1; } fun_avltree_unit* info = malloc(sizeof(fun_avltree_unit)); if(!info) { strcpy(bcl->msg,"malloc list fail"); return -1; } strncpy(info->remote_ip,(char *)inet_ntoa(recvAddr.sin_addr),sizeof(info->remote_ip)); info->remote_port = htons(recvAddr.sin_port); info->key = info->remote_ip; if(tree_add_remote_info(bcl,info) != 0) { strcpy(bcl->msg,"insert info fail"); free(info); return -1; } #ifdef BROADCAST_DEBUG printf("IP:%s\n", info->remote_ip); printf("Port:%d\n", info->remote_port); printf("receive a broadCast messgse:%s\n", recvbuf); #endif return 0; } else { #ifdef BROADCAST_DEBUG printf("recvfrom fail(%d): errno=%d\n",__LINE__, errno); #endif if(errno != EAGAIN){ sprintf(bcl->msg,"recvfrom: %m"); break; } } } while ((bcl->timeout==-1) || (get_timestamp_difftime(startTime,get_timestamp()) < bcl->timeout)); sprintf(bcl->msg,"timeout"); return -1; }

头文件:

#ifndef _WIN32 #include <sys/types.h> #include <netinet/in.h> #include <netdb.h> #include <sys/socket.h> #include <sys/wait.h> #include <arpa/inet.h> #include <sys/time.h> #else #include <winsock2.h> //链接时需要添加 -lwsock32 #include <windows.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdint.h> #include <malloc.h> #include <errno.h> #include "broadcast.h" #include "cJSON.h" #include "fun_runtime.h"

4.最后

        调试过程中很多坑,特别在windows下很多设置要特殊处理,如头文件winsock2要写在windows前面,设置参数不可以用(xxxx | xxxx)一次性设置,需要分开两次等等,还有其他设置项出错导致发送失败。

        好在最后都正常跑了,可喜可贺

5.代码

https://gitee.com/alaker/broadcast

今天的文章
tcp/udp搜索局域网主机的基本原理_广播域和冲突域的概念分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/80904.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注