1. 广播,组播代码
A.广播
1)发送端
#include <myhead.h> #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define IP "192.168.123.255" #define PORT 8888 int main(int argc, const char *argv[]) { int cfd = socket(AF_INET,SOCK_DGRAM,0); if(cfd < 0) { ERR_MSG("socket"); return -1; } printf("cfd = %d",cfd); int broad = 10; socklen_t optlen = sizeof(broad); if(setsockopt(cfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad)) <0) { ERR_MSG("setsockopt"); return -1; } printf("设置允许广播"); //绑定发送方的地址信息 ---》非必须绑定 //若不绑定则会自动绑定本机IP以及随机端口 //填充接收方的地址信息结构体,给下面的sendto函数使用 struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); sin.sin_addr.s_addr = inet_addr(IP); //广播IP char buf[128]=""; while(1) { //发送数据给接收方 bzero(buf,sizeof(buf)); if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0) { ERR_MSG("sendto"); return -1; } printf("sendto success\n"); } close(cfd); return 0; }
2)接收端
#include <myhead.h> #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define IP "192.168.123.255" #define PORT 8888 int main(int argc, const char *argv[]) { //创建报式套接字 int sfd = socket(AF_INET,SOCK_DGRAM,0); if(sfd < 0) { ERR_MSG("socket"); return -1; } printf("sfd = %d \n",sfd); //填充接收端的地址信息结构体,AF_INET --->man 7 ip struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); sin.sin_addr.s_addr = inet_addr(IP); //绑定接收端的地址信息 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))< 0) { ERR_MSG("bind"); return -1; } printf("bind success\n"); //存储数据包是从谁那里来的 struct sockaddr_in cin; socklen_t addrlen = sizeof(cin); char buf[128]= ""; while(1) { bzero(buf,sizeof(buf)); if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen) < 0) { ERR_MSG("recvfrom"); return -1; } printf("[%s : %d] : %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf); } //关闭套接字 close(sfd); return 0; }
B.组播
1)发送端
#include <myhead.h> #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define IP "224.1.2.3" #define PORT 8888 int main(int argc, const char *argv[]) { //创建报式套接字 int cfd = socket(AF_INET,SOCK_DGRAM,0); if(cfd<0) { ERR_MSG("socket"); return -1; } printf("cfd = %d\n",cfd); //填充接收方的地址信息结构体,给下面的sendto函数使用 struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); sin.sin_addr.s_addr= inet_addr(IP); //发送数据 char buf[128]=""; while(1) { bzero(buf,sizeof(buf)); printf("请输入--->"); fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1] = 0; if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0) { ERR_MSG("sendto"); return -1; } printf("sendto success\n"); } //关闭套接字 close(cfd); return 0; }
2)接收端
#include <myhead.h> #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define GRP_IP "224.1.2.3" //组播IP 224.0.0.0 - 239.255.255.255 #define LOL_IP "192.168.123.104" //ifconfig的本机IP #define PORT 8888 int main(int argc, const char *argv[]) { //创建报式套接字 int sfd = socket(AF_INET,SOCK_DGRAM,0); if(sfd<0) { ERR_MSG("socket"); return -1; } printf("sfd = %d\n",sfd); //加入多播组 struct ip_mreqn mq; mq.imr_multiaddr.s_addr = inet_addr(GRP_IP); //组播IP mq.imr_address.s_addr = inet_addr(LOL_IP); //本机IP mq.imr_ifindex = 0; //网络设备索引号 //设置多播组 if(setsockopt(sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mq,sizeof(mq))<0) { ERR_MSG("setsockopt"); return -1; } printf("加入 %s 小组 %d 端口成功\n",GRP_IP,PORT); //填充接收方的地址信息结构体 struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); sin.sin_addr.s_addr = inet_addr(GRP_IP); //绑定接收方的地址信息 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0) { ERR_MSG("bind"); return -1; } printf("bind success\n"); //存储数据包是从哪里来的 struct sockaddr_in cin; socklen_t addrlen = sizeof(cin); //接收数据 char buf[] = ""; while(1) { bzero(buf,sizeof(buf)); if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen) <0) { ERR_MSG("recvfrom"); return -1; } printf("[%s : %d] : %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf); } //关闭套接字 close(sfd); return 0; }
2. 多进程
#include <myhead.h> #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define IP "192.168.123.104" #define PORT 8888 int deal_cli_msg(int newfd ,struct sockaddr_in cin); void handler(int sig) { while(waitpid(-1,NULL,WNOHANG) > 0); } int main(int argc, const char *argv[]) { if(signal(SIGCHLD,handler) == SIG_ERR) { ERR_MSG("signal"); return -1; } printf("捕获17号信号成功\n"); int sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd < 0) { ERR_MSG("socket"); return -1; } //允许端口快速被重用 int reuse = 1; if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) <0) { ERR_MSG("setsockopt"); return -1; } printf("允许端口快速被重用成功\n"); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); sin.sin_addr.s_addr = inet_addr(IP); if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0) { ERR_MSG("bind"); return -1; } printf("bind success\n"); if(listen(sfd,128) < 0) { ERR_MSG("listen"); return -1; } printf("listen success\n"); struct sockaddr_in cin; socklen_t addrlen = sizeof(cin); pid_t cpid =0; int newfd = -1; while(1) { newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen); if(newfd <0) { ERR_MSG("accept"); return -1; } printf("[%s : %d] newfd = %d 客户端连接成功\n",\ inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); //能运行到当前位置,则代表有客户端连接成功了,则需要创建一个子进程用与手法数据 cpid = fork(); if(0 == cpid) { close(sfd); //子进程只负责与客户端交互 deal_cli_msg(newfd,cin); close(newfd); exit(0); //子进程只负责与客户端交互,所以当客户端退出后要退出子进程 } close(newfd); } //关闭文件描述符 if(close(sfd)<0) { ERR_MSG("close"); return -1; } return 0; } int deal_cli_msg(int newfd ,struct sockaddr_in cin) { char buf[128] = ""; ssize_t res = 0; while(1) { bzero(buf,sizeof(buf)); res = recv(newfd,buf,sizeof(buf),0); if(res<0) { ERR_MSG("recv"); return -1; } else if(0 == res) { printf("[%s ; %d] newfd = %d 客户端下线\n",\ inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); break; } printf("[%s ; %d] newfd=%d ; %s\n",\ inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf); //发送数据 strcat(buf,"Q_A_Q"); //可以修改成从其他地方获取 if(send(newfd,buf,sizeof(buf),0)<0) { ERR_MSG("send"); return -1; } printf("发送成功\n"); } return 0; }
3. 多线程
#include <myhead.h> #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define IP "192.168.123.104" #define PORT 8888 struct cliinfo { int newfd; struct sockaddr_in cin; }; void *deal_cli_msg(void* arg); //void * arg = &msg int main(int argc, const char *argv[]) { //创建流式套接字 int sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd < 0) { ERR_MSG("socket"); return -1; } //允许端口快速被重用 int reuse = 1; if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) <0) { ERR_MSG("setsockopt"); return -1; } printf("允许端口快速被重用成功\n"); //填充服务器的地址信息结构体 struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); sin.sin_addr.s_addr = inet_addr(IP); //绑定服务器的IP和端口---》必须绑定 if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0) { ERR_MSG("bind"); return -1; } printf("bind success\n"); //将套接字设置为被动监听状态,监听是否有客户端连接 if(listen(sfd,128) < 0) { ERR_MSG("listen"); return -1; } printf("listen success\n"); struct sockaddr_in cin; socklen_t addrlen = sizeof(cin); int newfd = -1; pthread_t tid; struct cliinfo msg; while(1) { //主线程只负责连接 accept //阻塞函数,阻塞等待客户端连接成功 从已完成连接的队列头中获取一个客户端信息 //这个新的文件描述符,才是与客户端通信的文件描述符 newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen); if(newfd <0) { ERR_MSG("accept"); return -1; } printf("[%s : %d] newfd = %d 客户端连接成功\n",\ inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); msg.newfd = newfd; msg.cin = cin; //能运行到当前位置,则代表有客户端连接成功了,则需要创建一个子进程用与手法数据 if(pthread_create(&tid,NULL,deal_cli_msg,(void *)&msg) !=0 ) { fprintf(stderr,"pthread_create failed __%d__\n",__LINE__); return -1; } pthread_detach(tid); //分离线程,线程退出后由内核自动回收 } //关闭文件描述符 if(close(sfd)<0) { ERR_MSG("close"); return -1; } return 0; } void * deal_cli_msg(void * arg) { int newfd = ((struct cliinfo*)arg)->newfd; struct sockaddr_in cin = ((struct cliinfo*)arg)->cin; char buf[128] = ""; ssize_t res = 0; while(1) { bzero(buf,sizeof(buf)); //接收数据 res = recv(newfd,buf,sizeof(buf),0); if(res<0) { ERR_MSG("recv"); break; } else if(0 == res) { printf("[%s ; %d] newfd = %d 客户端下线\n",\ inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); break; } printf("[%s ; %d] newfd=%d ; %s\n",\ inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf); //发送数据 strcat(buf,"QAQ"); //可以修改成从其他地方获取 if(send(newfd,buf,sizeof(buf),0)<0) { ERR_MSG("send"); break; } printf("发送成功\n"); } close(newfd); pthread_exit(NULL); }