上一部分大致提了一下UDP通信要用到的API,下面就要开始实际测试了,先搞服务端,再搞客户端。
Linux环境下的UDP/TCP网络通信API接口函数_abs(ln(1+NaN))的博客-****博客/challenglistic/article/details/125673808?spm=1001.2014.3001.5501
目录
一、服务端
1、创建(服务端)套接字
2、绑定IP和端口号
3、接收来自客户端的数据
4、给客户端发送数据(响应客户端)
二、客户端
1、创建套接字
2、填写服务器的地址信息
3、从键盘获取内容并发送给服务端
三、测试结果
一、服务端
1、创建(服务端)套接字
使用的函数是socket函数,即告诉编译器,你的服务器的通信方式、通信协议。我们的通信方式就选择网络通信AF_INET,通信协议选择UDP
//1. 创建服务端套接字
int server = socket(AF_INET,SOCK_DGRAM,0);
if(server<0)
{
std::cerr<<"socket创建失败"<<std::endl;
return 1;
}
2、绑定IP和端口号
服务器一般都是被动接收其他主机的请求,而且服务器可以有多个网卡,即IP地址。如果服务器希望接收来自多个主机的数据,那么就无需主动绑定IP,但是必须要绑定端口号。因为即便IP有多个,端口一般就一个。
创建套接字的时候,既然选择的通信方式是AF_INET,用于存放服务端地址的数据类型那就是struct sockaddr_in。但是在填入bind函数的时候,bind函数使用的是统一接口,所以需要强转成struct sockaddr* 类型。
//2. 绑定IP端口号
// a.填充地址信息
struct sockaddr_in local;
local.sin_family = AF_INET; //选择协议家族(通信方式)AF_INET
uint16_t port = 8080;
local.sin_port = htons(port); //绑定端口,因为port是16位int型变量,是主机序列,需要转化为网络字节序
local.sin_addr.s_addr = INADDR_ANY; //如果是接收绑定指定ip的数据,那就是inet_addr("你的ip")
//如果不指定,那就是INADDR_ANY,表明凡是发送到8080端口的
//数据,你都选择接收,不管是服务器上哪个ip地址收到的
// b.使用bind函数绑定
int ret = bind(server,(struct sockaddr*)&local,sizeof(local));
if (ret<0)
{
//说明绑定失败
std::cerr<<"bind绑定失败"<<errno<<std::endl;
return 2;
}
3、接收来自客户端的数据
绑定端口后,现在只需要等待接收来自其他客户端的消息。我们使用recvfrom函数来接收,在接收到数据以后,将收到的信息打印出来。
while (1)
{
/*********接收来自客户端的数据*********/
char buffer[1024]; //用于存放对方发送的数据
struct sockaddr_in src; //用于保存对端的地址信息
socklen_t len = sizeof(src); //对端地址信息的大小
recvfrom(server,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&src,&len);
std::cout<<"client# "<< buffer <<std::endl;
}
4、给客户端发送数据(响应客户端)
接收到数据以后,我们把接收到的数据发回给客户端,一般是做一些处理,再把处理结果发送给客户端。我们使用的是sendto函数,第四个参数是客户端的地址信息,我们上一步正好获取到了客户端的地址信息,这里就可以直接拿来用了。
while (1)
{
/*********接收来自客户端的数据*********/
char buffer[1024]; //用于存放对方发送的数据
struct sockaddr_in src; //用于保存对端的地址信息
socklen_t len = sizeof(src); //对端地址信息的大小
recvfrom(server,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&src,&len);
std::cout<<"client# "<< buffer <<std::endl;
std::string msg = "收到来自客户端的信息:";
(buffer);
sendto(server,msg.c_str(),(),0,(struct sockaddr*)&src,len);
}
二、客户端
1、创建套接字
客户端也需要套接字来承载地址信息,使用的函数也是socket函数
//创建客户端套接字
int client = socket(AF_INET,SOCK_DGRAM,0);
if(client<0){
std::cerr << "socket创建失败" << std::endl;
return 1;
}
2、填写服务器的地址信息
在上一篇讲bind函数的用法时,提到这个问题,客户端无需显式的绑定端口号,假设你绑定的端口号为40,然而你并不知道40号端口是否被其他应用程序占用。因此,一般客户端无需显式的绑定端口,绑定端口的任务就交给OS,它最清楚哪个端口没有被占用。
我们需要做的是准备好服务器的地址信息,以用于下面的sendto函数
//客户端要给谁发??
struct sockaddr_in dst;
dst.sin_family = AF_INET;
dst.sin_port = htons(8080); //服务器的端口号
dst.sin_addr.s_addr = inet_addr("124.222.215.205"); //服务器的ip地址
3、从键盘获取内容并发送给服务端
while (1)
{
//从键盘获取内容
std::string msg;
std::cout<<"client# ";
std::cin>>msg;
//向服务器发送数据
socklen_t len = sizeof(dst);
sendto(client,msg.c_str(),(),0,(struct sockaddr*)&dst,len);
char buffer[1024];
//接收服务器做出的响应
int ret = recvfrom(client,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&dst,&len);
if(ret>0){
std::cout<<"server# "<< buffer <<std::endl;
}
}