1.udp流程
谁先发送,谁就是发送端
发送端 接收端
创建套接字socket 创建套接字socket
绑定bind 绑定bind
收发信息sendto/recvfrom 收发信息sendto/recvfrom
关闭套接字close 关闭套接字close
2.相关的接口函数
(1)发送信息
ssize_t sendto(int socket,void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
返回值:发送的字节数
-1
参数:前面四个参数跟send一模一样
dest_addr --》存放对方的ip和端口号(需要我们自己主动填写)
dest_len --》地址结构体的大小
(2)接收信息
ssize_t recvfrom(int socket, void *buffer, size_t length,int flags, struct sockaddr *address, socklen_t *address_len);
返回值:接收的字节数
-1
注意:recv函数跟recvfrom是不一样的,recv如果对方断开连接,recv不再阻塞,然后返回0
recvfrom如果对方退出,依然阻塞,不受任何影响
参数:前面四个参数跟recv一模一样
address --》存放对方的ip和端口号(不需要我们自己主动填写,接收信息成功,recvfrom函数会自动把发送信息的那个主机的ip和端口号填写到这个变量地址中)
address_len --》地址结构体的大小 要求是指针3.udp广播
(1)概念
发送给局域网中所有在线的主机
比如:咱们这个教室192.168.26.xxxx
192.168.26 --》网段/网络号(区分不同的局域网)
xxxx --》主机号(区分同一个局域网中的不同主机)
主机号取值范围正常:0---255之间,但是0不使用,255作为广播专用地址
(2)实现流程
广播发送端 广播接收端
创建套接字socket 创建套接字socket
绑定bind 绑定bind
设置套接字的属性为可以广播
发送广播信息 接收广播信息recvfrom
关闭套接字close 关闭套接字close
(3)如何设置套接字的属性为可以广播
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
(4)如果使用udp广播,bind的时候不可以使用具体的ip,必须使用系统的宏定义INADDR_ANY
INADDR_ANY的含义:自动匹配本地主机上的任意一个ip地址
bindaddr.sin_addr.s_addr=htonl(INADDR_ANY);4.理论知识
(1)ip地址分类 A B C D四类地址
见图示
(2)tcp和udp区别
tcp:有连接的可靠的通信方式
udp:无连接的不可靠的通信方式
有连接和无连接:
tcp通信双方在正式通信之前,必须经历三次握手(客户端跟服务器之间互相确认身份),确定双方的身份以后才能通信
udp通信双方在正式通信之前,没有三次握手这个说法,也不需要确定对方的身份
可靠和不可靠(相对的)
tcp不容易丢失数据包,支持错误重传,错误校验(用于通信要求高的场合)
udp网络拥堵的时候,很容易丢失数据包,不支持错误校验,重传, udp用于通信要求不高的场合(视频点播)
(3)配置ip地址
方法一:图形用户界面配置
照着window的信息去配置,只有主机号不同,其他的照抄
方法二:使用配置文件配置
/etc/network/interfaces这个文件
auto lo
iface lo inet loopbackauto ens33
iface ens33 inet static
address 192.168.26.xxxx
gateway 192.168.26.1 //网关
netmask 255.255.255.0 //子网掩码
dns-nameservers 202.96.134.133 //DNS服务器
udp单向通讯
#include "myhead.h"
int main()
{
int udpsock;
int ret;
char sbuf[100];
//定义ipv4地址结构体变量
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=inet_addr("192.168.1.50"); //发送端自己的ip地址
bindaddr.sin_port=htons(10001); //发送端的端口号
//定义ipv4地址结构体变量存放对方的ip和端口号
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=inet_addr("192.168.1.50"); //对方的ip地址
serveraddr.sin_port=htons(20000); //对方的端口号
//创建udp套接字
udpsock=socket(AF_INET,SOCK_DGRAM,0);
if(udpsock==-1)
{
perror("创建失败!\n");
return -1;
}
//取消端口绑定的限制
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定
ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
perror("绑定ip和端口号失败!\n");
return -1;
}
//直接开始聊天,发送信息了
while(1)
{
bzero(sbuf,100);
printf("请输入要发送的内容:\n");
scanf("%s",sbuf);
sendto(udpsock,sbuf,strlen(sbuf),0,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
}
}
#include "myhead.h"
int main()
{
int udpsock;
int ret;
char sbuf[100];
//定义ipv4地址结构体变量
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=inet_addr("192.168.1.50"); //接收端自己的ip地址
bindaddr.sin_port=htons(20000); //接收端的端口号
//定义ipv4地址结构体变量存放对方的ip和端口号
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
int addrsize=sizeof(serveraddr);
//创建udp套接字
udpsock=socket(AF_INET,SOCK_DGRAM,0);
if(udpsock==-1)
{
perror("创建失败!\n");
return -1;
}
//取消端口绑定的限制
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定
ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
perror("绑定ip和端口号失败!\n");
return -1;
}
//直接开始聊天,接收信息了
while(1)
{
bzero(sbuf,100);
recvfrom(udpsock,sbuf,100,0,(struct sockaddr *)&serveraddr,&addrsize);
printf("%s:%hu的这台主机发送信息过来了:%s\n",inet_ntoa(serveraddr.sin_addr),ntohs(serveraddr.sin_port),sbuf);
}
}
udp双向通讯
#include "myhead.h"
int udpsock;
void *recvmsgfrom(void *arg)
{
char rbuf[100];
struct sockaddr_in otheraddr;
int addrsize=sizeof(otheraddr);
while(1)
{
bzero(rbuf,100);
recvfrom(udpsock,rbuf,100,0,(struct sockaddr *)&otheraddr,&addrsize);
printf("回复的信息是:%s\n",rbuf);
}
}
int main()
{
pthread_t id;
int ret;
char sbuf[100];
//定义ipv4地址结构体变量
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=inet_addr("192.168.16.51"); //发送端自己的ip地址
bindaddr.sin_port=htons(10001); //发送端的端口号
//定义ipv4地址结构体变量存放对方的ip和端口号
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=inet_addr("192.168.16.51"); //对方的ip地址
serveraddr.sin_port=htons(20000); //对方的端口号
//创建udp套接字
udpsock=socket(AF_INET,SOCK_DGRAM,0);
if(udpsock==-1)
{
perror("创建失败!\n");
return -1;
}
//取消端口绑定的限制
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定
ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
perror("绑定ip和端口号失败!\n");
return -1;
}
//创建子线程接收信息
pthread_create(&id,NULL,recvmsgfrom,NULL);
//直接开始聊天,发送信息了
while(1)
{
bzero(sbuf,100);
printf("请输入要发送的内容:\n");
scanf("%s",sbuf);
sendto(udpsock,sbuf,strlen(sbuf),0,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
}
}
#include "myhead.h"
int udpsock;
//定义ipv4地址结构体变量存放对方的ip和端口号
struct sockaddr_in serveraddr;
void *sendtoother(void *arg)
{
char rbuf[100];
while(1)
{
bzero(rbuf,100);
printf("请输入要发送的内容!\n");
scanf("%s",rbuf);
sendto(udpsock,rbuf,strlen(rbuf),0,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
}
}
int main()
{
pthread_t id;
int ret;
char sbuf[100];
//定义ipv4地址结构体变量
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=inet_addr("192.168.16.51"); //接收端自己的ip地址
bindaddr.sin_port=htons(20000); //接收端的端口号
bzero(&serveraddr,sizeof(serveraddr));
int addrsize=sizeof(serveraddr);
//创建udp套接字
udpsock=socket(AF_INET,SOCK_DGRAM,0);
if(udpsock==-1)
{
perror("创建失败!\n");
return -1;
}
//取消端口绑定的限制
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定
ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
perror("绑定ip和端口号失败!\n");
return -1;
}
//创建线程发送信息
pthread_create(&id,NULL,sendtoother,NULL);
//直接开始聊天,接收信息了
while(1)
{
bzero(sbuf,100);
recvfrom(udpsock,sbuf,100,0,(struct sockaddr *)&serveraddr,&addrsize);
printf("%s:%hu的这台主机发送信息过来了:%s\n",inet_ntoa(serveraddr.sin_addr),ntohs(serveraddr.sin_port),sbuf);
}
}
udp广播
#include "myhead.h"
int main()
{
int udpsock;
int ret;
char sbuf[100];
//定义ipv4地址结构体变量
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //绑定本地主机上的任意一个ip地址
bindaddr.sin_port=htons(10001); //发送端的端口号
//定义ipv4地址结构体变量存放对方的ip和端口号
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=inet_addr("192.168.26.255"); //发送给192.168.26这个局域网中的所有主机
serveraddr.sin_port=htons(20000); //对方的端口号
//创建udp套接字
udpsock=socket(AF_INET,SOCK_DGRAM,0);
if(udpsock==-1)
{
perror("创建失败!\n");
return -1;
}
//取消端口绑定的限制
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定
ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
perror("绑定ip和端口号失败!\n");
return -1;
}
//把套接字的属性设置为可以广播
setsockopt(udpsock,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
//发送广播信息
while(1)
{
bzero(sbuf,100);
printf("请输入要发送的广播信息:\n");
scanf("%s",sbuf);
sendto(udpsock,sbuf,strlen(sbuf),0,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
}
}
#include "myhead.h"
int main()
{
int udpsock;
int ret;
char sbuf[100];
//定义ipv4地址结构体变量
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=htonl(INADDR_ANY); //绑定本地主机上的任意一个ip地址
bindaddr.sin_port=htons(20000); //接收端的端口号
//定义ipv4地址结构体变量存放对方的ip和端口号
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
int addrsize=sizeof(serveraddr);
//创建udp套接字
udpsock=socket(AF_INET,SOCK_DGRAM,0);
if(udpsock==-1)
{
perror("创建失败!\n");
return -1;
}
//取消端口绑定的限制
int on=1;
setsockopt(udpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定
ret=bind(udpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
if(ret==-1)
{
perror("绑定ip和端口号失败!\n");
return -1;
}
//接收广播信息
while(1)
{
bzero(sbuf,100);
recvfrom(udpsock,sbuf,100,0,(struct sockaddr *)&serveraddr,&addrsize);
printf("%s:%hu的这台主机发送的广播信息是:%s\n",inet_ntoa(serveraddr.sin_addr),ntohs(serveraddr.sin_port),sbuf);
}
}
UDP通信流程与实践:从单向到广播
本文详细介绍了UDP协议的通信流程,包括从创建套接字、绑定、收发信息到关闭套接字的步骤。特别强调了UDP的单向通讯和双向通讯的实现,以及如何进行UDP广播。同时,对比了UDP与TCP在连接性和可靠性上的区别,并提供了IP地址配置的相关知识。
8636

被折叠的 条评论
为什么被折叠?



