linux_C语言_udp的多种实现方法
- 最基本的方式(不用组播不用sigio信号不使能广播属性)
- 接收端
- 发送端
- 使用SIGIO信号的方式(使用sigio信号使用广播使能属性)
- 服务端
- 客户端
- 使用组播模式
- 服务端
- 客户端
- tcp和udp的使用区别
- 所有源码下载点这~~
最基本的方式(不用组播不用sigio信号不使能广播属性)
接收端
// 1,创建UDP套接字
int fd = Socket(AF_INET, SOCK_DGRAM, 0);// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);addr.sin_family = AF_INET;
inet_aton("192.168.45.153", &addr.sin_addr); // 绑定指定的IP,并做了字节序转换
//addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定自动获取的IP好像一般为0.0.0.0
addr.sin_port = htons(50001);// 3,绑定地址
Bind(fd, (struct sockaddr *)&addr, len);// 5,静静地等待对方的信件...
char buf[100];
int flag=0;
while (1)
{// 4,准备接受对方的地址信息struct sockaddr_in peeraddr;len = sizeof(peeraddr);bzero(&peeraddr, len);bzero(buf, 100);if (recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len) != 0)//此函数用于UDP套接字接受数据{flag = 1;}printf("收到【%s:%hu】的信息: %s",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);if (flag == 1){sendto(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, len);//此函数用于向UDP套接字发送数据flag = 0;}printf("发送完毕\n");
}
发送端
char buf[100];
// 1,创建UDP套接字
int fd = Socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);addr.sin_family = AF_INET;
inet_aton("192.168.45.153", &addr.sin_addr); // 绑定指定的IP,并做了字节序转换(字符串转二进制)
// addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定自动获取的IP
addr.sin_port = htons(50001);while (1)
{bzero(buf, 100);scanf("%s", buf);getchar();sendto(fd, buf, 100, 0, (struct sockaddr *)&addr, len);printf("发送完毕\n");// 4,准备接受对方的地址信息struct sockaddr_in peeraddr;len = sizeof(peeraddr);bzero(&peeraddr, len);// 5,静静地等待对方的信件...buf[100];bzero(buf, 100);recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);printf("收到【%s:%hu】的信息: %s",inet_ntoa(peeraddr.sin_addr),//字节序转换(二进制转)ntohs(peeraddr.sin_port),buf);
}
使用SIGIO信号的方式(使用sigio信号使用广播使能属性)
服务端
注意事项:
因为客户端会使能广播属性向所有地址(255.255.255.255)进行数据发送
所以这里不能特定指定服务器为某网卡ip地址:inet_aton(“192.168.45.153”, &addr.sin_addr);
这会导致客户端那边发送服务器接受数据失败的情况
// 1,创建UDP套接字
fd = Socket(AF_INET, SOCK_DGRAM, 0);// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);addr.sin_family = AF_INET;
//inet_aton("x.x.x.x", &addr.sin_addr); // 绑定指定的IP,并做了字节序转换
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定一个本机的任意可用IP
// inet_aton("192.168.45.153", &addr.sin_addr);//这里需要注意使能广播属性后不能指定IP,不然客户端对255.255.255.255广播地址进行数据发送会接受不到统一用INADDR_ANY
addr.sin_port = htons(50002);// 3,绑定地址
Bind(fd, (struct sockaddr *)&addr, len);// 4,用信号的方式来异步地接收各个客户端发来的UDP信息...// a. 捕捉信号SIGIO
signal(SIGIO, f);// b. 设置套接字为异步工作模式(即使之收到数据是产生信号SIGIO)
long flag = fcntl(fd, F_GETFL);
flag |= O_ASYNC;
fcntl(fd, F_SETFL, flag);// c. 指定本进程为信号的属主
fcntl(fd, F_SETOWN, getpid());// 服务器忙别的事情
int i=0;
while(1)
{i++;printf("%d\n",i);sleep(1);
}
// 准备接受对方的地址信息
struct sockaddr_in peeraddr;
socklen_t len = sizeof(peeraddr);
bzero(&peeraddr, len);char buf[100];
bzero(buf, 100);
recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len); printf("收到【%s:%hu】的信息: %s",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);
// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
len = sizeof(addr);
bzero(&addr, len);addr.sin_family = AF_INET;
inet_aton("255.255.255.255", &addr.sin_addr); // 准备好客户端的IP
addr.sin_port = htons(ntohs(peeraddr.sin_port)); // 准备好客户端的PORT
// 3,使能广播属性
int on = 1;
Setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));sendto(fd, buf, 100, 0, (struct sockaddr *)&addr, len);
客户端
// 1,创建UDP套接字
int fd = Socket(AF_INET, SOCK_DGRAM, 0);
int ret;
// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);// 4,广播消息
char buf[100];while(1)
{bzero(&addr, len);addr.sin_family = AF_INET;inet_aton("255.255.255.255", &addr.sin_addr); // 准备好服务器的IP// inet_aton("192.168.45.153", &addr.sin_addr);addr.sin_port = htons(50002); // 准备好服务器的PORT// 3,使能广播属性int on = 1;Setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));bzero(buf, sizeof(buf));fgets(buf,100,stdin);ret = sendto(fd, buf, 100, 0, (struct sockaddr *)&addr, len);printf("RETURN %d\n",ret);// 准备接受对方的地址信息struct sockaddr_in peeraddr;socklen_t len = sizeof(peeraddr);bzero(&peeraddr, len);char buf[100];bzero(buf, 100);recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);printf("收到【%s:%hu】的信息: %s",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);
}
使用组播模式
服务端
// 1,创建UDP套接字
int fd = socket(AF_INET, SOCK_DGRAM, 0);// 2,准备地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(atoi(argv[1]));// 3,绑定地址
bind(fd, (struct sockaddr *)&addr, len);// 4,使能广播属性
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));// 5,准备好组播地址结构体
struct sockaddr_in addr2;
socklen_t len2 = sizeof(addr2);
bzero(&addr2, len2);addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr("224.0.0.100");
addr2.sin_port = htons(50003);// 6,静静地等待客户端的数据
char buf[100];
while(1)
{struct sockaddr_in peeraddr;socklen_t len = sizeof(peeraddr);bzero(&peeraddr, len);bzero(buf, 100);recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);printf("收到【%s:%hu】的信息: %s",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);// 转发到组播中if(sendto(fd, buf, strlen(buf), 0,(struct sockaddr *)&addr2, len2) == -1){perror("sendto failed");}
}
客户端
// 1,创建UDP套接字
fd = socket(AF_INET, SOCK_DGRAM, 0);// 2,准备存放自身地址的结构体
struct sockaddr_in myaddr;
socklen_t mylen = sizeof(myaddr);
bzero(&myaddr, mylen);myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(50003);// 3,绑定固定的地址,方便服务器主动给我发数据
bind(fd, (struct sockaddr *)&myaddr, mylen);// 4,加入指定的多播组
struct ip_mreq m;
bzero(&m, sizeof(m));m.imr_multiaddr.s_addr = inet_addr("224.0.0.100");
m.imr_interface.s_addr = htonl(INADDR_ANY);setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m));// a. 捕捉信号SIGIO
signal(SIGIO, f);// b. 设置套接字为异步工作模式(即使之收到数据是产生信号SIGIO)
long flag = fcntl(fd, F_GETFL);
flag |= O_ASYNC;
fcntl(fd, F_SETFL, flag);// c. 指定本进程为信号的属主
fcntl(fd, F_SETOWN, getpid());// 5,准备对端服务器的地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));// 6,不断给服务器发送数据
// 当收到服务器发来的组播消息时,会触发SIGIO
// 继而会使得 fgets() 出错返回
char buf[100];
while(1)
{bzero(buf, 100);if(fgets(buf, 100, stdin) == NULL){perror("fgets failed");continue;}sendto(fd, buf, strlen(buf), 0,(struct sockaddr *)&addr, len);
}
tcp和udp的使用区别
tcp具有可靠性所以一般用于cmd命令的一些重要信息收发
udp则速度比较快,一般用于数据的发送比如音视频数据