UDP通信
1. UDP
代码实现流程如下所示
UDP通信过程
//服务器端
1. socket() 创建套接字
2. bind() 绑定套接字
与TCP区别开来,没有listen()、accept()建立连接的过程
3. 通信 recvfrom() sendto()
4. close
//客户端
1. socket() 创建套接字
与TCP区别开来,没有connect()建立连接的过程
2. 通信 sendto() recvfrom()
3. close()
//UDP 服务器端 - udpServer.cpp
int main(){
int fd = socket(PF_INET, SOCK_DGRAM, 0);
//注意SOCK_DGRAM TCP对应的第二个参数是SOCK_STREAM
if(fd == -1){
perror("udpServer.cpp socket() errors");
exit(-1);
}
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8888);
int ret = bind(fd, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if(ret == -1){
perror("udpServer.cpp bind() errors");
exit(-1);
}
while(1){
char buf[BUFSIZ];
char ipBuf[16];
struct sockaddr_in clientAddr;
socklen_t size = sizeof(clientAddr);
int len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) &clientAddr, &size);
cout << "client IP = " << inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, ipBuf, sizeof(ipBuf))
<< "client PORT = " << ntohs(clientAddr.sin_port) << endl;
cout << "server recv : " << buf << endl;
sendto(fd, buf, strlen(buf) + 1, 0, (struct sockaddr *) &clientAddr, sizeof(clientAddr));
}
close(fd);
return 0;
}
//UDP 客户端 - udpClient.cpp
int main() {
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
struct sockaddr_in clientAddr;
clientAddr.sin_family = AF_INET;
clientAddr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &clientAddr.sin_addr.s_addr);
int num = 0;
while(1) {
char buf[BUFSIZ];
sprintf(buf, "hello , i am client %d \n", num++);
sendto(fd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&clientAddr, sizeof(clientAddr));
int len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
cout << "client recv : " << buf << endl;
sleep(1);
}
close(fd);
return 0;
}
2. 广播与组播
先讲讲 广播 与后面要实现的 组播(多播) 的区别
广播:向子网中的多台计算机发送消息。
1.特征:
IP地址由网络号+主机号构成,而广播则是主机标识部分全为1,即必须满足 *.*.*.255结尾
2.应用:
A.只能在局域网中使用;
B.客户端需要绑定服务使用的端口,才能收到广播消息。
3.实现:
设置广播属性的函数setsockport()
组播(多播):
1.联系:
A.单播地址标识单个IP接口;
B.广播地址表示某个子网的所有IP接口;
C.多播地址标识一组IP接口,是前两种的折中方案。
2.应用:
A.既可以用于局域网,又可以用于跨广域网;
B.客户端需要加入多播组,才能接受到多播的数据。
广播图
组播图(多播):
广播代码实现流程如下所示
广播通信
//服务器端
1. socket() 创建套接字
2. setsockpot()设置广播属性
3. 创建一个广播的地址 inet_pton
4. 通信 recvfrom() sendto()
5. close
//客户端
1. socket() 创建套接字
2. 客户端绑定本地的IP和PORT
3. 通信 sendto() recvfrom()
4. close()
广播代码实现如下所示
//广播 服务器端
int main() {
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
int op = 1;
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));
struct sockaddr_in cliaddr;
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(9999);
inet_pton(AF_INET, "172.25.191.255", &cliaddr.sin_addr.s_addr);
int num = 0;
while(1) {
char sendBuf[128];
sprintf(sendBuf, "hello, client....%d\n", num++);
// 发送数据
sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
printf("广播的数据:%s\n", sendBuf);
sleep(1);
}
close(fd);
return 0;
}
//广播 客户端端
int main() {
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
struct in_addr in;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
while(1) {
char buf[128];
int num = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
printf("server say : %s\n", buf);
}
close(fd);
return 0;
}
组播实现流程如下所示:
多播通信
//服务器端
1. socket() 创建套接字
2. setsockpot()设置多播属性
3. 初始化客户端的地址信息 IP PORT
4. 通信 recvfrom() sendto()
5. close
//客户端
1. socket() 创建套接字
2. 客户端bind绑定本地的IP和PORT
3. setsockopt加入多播组
4. 通信 sendto() recvfrom()
5. close()
//多播服务器端
int main() {
// 1.创建一个通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
// 2.设置多播的属性,设置外出接口
struct in_addr imr_multiaddr;
// 初始化多播地址
inet_pton(AF_INET, "239.0.0.10", &imr_multiaddr.s_addr);
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &imr_multiaddr, sizeof(imr_multiaddr));
// 3.初始化客户端的地址信息
struct sockaddr_in cliaddr;
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(9999);
inet_pton(AF_INET, "239.0.0.10", &cliaddr.sin_addr.s_addr);
// 3.通信
int num = 0;
while(1) {
char sendBuf[128];
sprintf(sendBuf, "hello, client....%d\n", num++);
// 发送数据
sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
printf("组播的数据:%s\n", sendBuf);
sleep(1);
}
close(fd);
return 0;
}
//多播客户端
int main() {
// 1.创建一个通信的socket
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1) {
perror("socket");
exit(-1);
}
struct in_addr in;
// 2.客户端绑定本地的IP和端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
struct ip_mreq op;
inet_pton(AF_INET, "239.0.0.10", &op.imr_multiaddr.s_addr);
op.imr_interface.s_addr = INADDR_ANY;
// 加入到多播组
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &op, sizeof(op));
// 3.通信
while(1) {
char buf[128];
// 接收数据
int num = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
printf("server say : %s\n", buf);
}
close(fd);
return 0;
}