linux网络中UDP协议构造一个服务端和客户端的流程总结
**
因为本人之前一直写的是云笔记,对自己学会的东西作一个总结,所以基本都是文字,本来想全发成博客的形式,发现全发成博客比较花费时间,而且一直发博客质量不是很好,而且通过发博客学到的东西也会变少,所以准备先把笔记发出来,后续再将它们改成博客的形式,争取2天至少改一篇博客,觉得我总结的还行的可以先关注我,后续会发成博客形式,内容也会更加完善
**
UDP的服务端:
在进行套接字编程时,通常将需要的用到套接字函数在类中进行封装,增加一些其它的功能,或者是做一些防错措施,以及完善这些函数的流程,所以将这些函数集中在类中是很有作用的
我们在搭建UDP服务端时,通常是用main函数自带的三个参数来获取用户的输入信息,这个输入信息是我们在发送数据时要用的的IP地址和所用到的端口号,然后分别创建两个字符串对象来存储它们,方便一会在进行UDP传输时传入参数,然后我们一般创建一个之前写好的,UDP套接字函数对象(通过调用里面的函数来实现UDP数据报传输),因为UDP是单向的传输,不用管对端,也就是不用建立连接,所以我们可以直接调用之前封装好的socket函数,进行套接字的创建,然后再调用封装好的bind函数,来进行地址信息的绑定,因为我们现在是服务端,所以一般情况下自己绑定自己的IP地址,然后再绑定自己规定的端口号,所以这两个信息我们要传入bind函数中,当地址信息绑定完成后,就可以开始发送和接收数据了,因为我们是服务端,所以一般是先等待客户端给我们发送请求数据,然后我们再获取客户端的地址信息,发送对应的数据包给它们,所以我们先调用封装好的recvfrom函数进行接收,因为我们不知道服务端的数据包什么时候过来,所以就得一直等待服务端,所以一般情况下我们要接收客户端的数据时,就写个while(1),让它一直循环接收,如果接收到了,我们就获取到了客户端的地址信息,进而我们就可以调用封装好的sendto函数,进行数据的发送,在所有信息都传递完成,且后续不需要再接收客户端信息时,我们就可以调用封装好的close函数,关闭套接字
我们在搭建UDP客户端时,通常是用main函数自带的三个参数来获取用户的输入信息,这个输入信息是服务端的IP地址和所用到的端口号,然后分别创建两个字符串对象来存储它们,方便一会在进行UDP传输时传入参数,然后我们一般创建一个之前写好的,UDP套接字函数对象(通过调用里面的函数来实现UDP数据报传输),因为UDP是单向的传输,不用管对端,也就是不用建立连接,所以我们可以直接调用之前封装好的socket函数,进行套接字的创建,另外有一点要说明,一般情况下UDP的客户端不建议自己绑定地址信息,服务端需要绑定地址信息的原因是,如果服务端不绑定地址信息,那么客户端就不能确定服务端到底是用什么地址来接收数据包的,所以客户就不能向服务传输数据包了,但是客户端的话就不一样了,因为客房端是向服务请求数据包的,也就是客户端先向服务端发送数据包,服务端在接收到数据包后,可以获取客户端的地址信息,进而也就可以给客户端发送数据包了,所以客户端可以不绑定地址信息,而且客户端不绑定地址信息的好处也有很多,比如我第一次向服务端请求数据包时,用的是一个网卡上的IP地址,但过了一阵时间,我换了一个网卡,我的地址信息变了,但是由于我没有绑定地址信息,所以我仍可以向服务端请求数据包,所以客户端一般不建议绑定地址信息,所以现在我们就可以直接根据服务端的地址信息,利用我们封装好的sendto函数,向服务端发送数据包了,我们给服务端发送完数据包后,就可以等待服务端给我们回复数据包了,因为我们不知道服务端的数据包什么时候过来,所以就得一直等待服务端,所以一般情况下我们要接收服务端的数据时,就写个while(1),让它一直循环接收,如果接收到了,我们就获取到了服务端的地址信息在所有信息都传递完成,且后续不需要再接收客户端信息时,我们就可以调用封装好的close函数,关闭套接字
在构建服务端和客户端前封装的udp函数类:
#include <iostream>
#include <string>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define CHECK_RET(q) if((q) == false){return -1;}
class UdpSocket
{
public:
UdpSocket(){
}
~UdpSocket(){
}
bool Socket(){
_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (_sock < 0) {
perror("socket error");
return false;
}
return true;
}
bool Bind(std::string &ip, uint16_t port){
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
socklen_t len = sizeof(struct sockaddr_in);
int ret = bind(_sock, (struct sockaddr*)&addr, len);
if (ret < 0) {
perror("bind error");
return -1;
}
return true;
}
bool Recv(std::string &buf, sockaddr_in *_addr = NULL){
char tmp[1024] = {0};
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
int ret = recvfrom(_sock, tmp, 1024, 0,
(struct sockaddr*)&addr, &len);
if (ret < 0) {
perror("recvfrom error");
return false;
}
buf.assign(tmp, ret);
if (_addr != NULL) {
memcpy(_addr, &addr, len);
}
return true;
}
bool Send(std::string &buf, struct sockaddr_in &addr){
socklen_t len = sizeof(struct sockaddr_in);
int ret = sendto(_sock, buf.c_str(), buf.size(), 0,
(struct sockaddr*)&addr, len);
if (ret < 0) {
perror("sendto error");
return false;
}
return true;
}
bool Close(){
close(_sock);
_sock = -1;
return true;
}
private:
int _sock;
};
服务端:
#include "udpsocket.hpp"
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("./udp_srv ip port\n");
return -1;
}
std::string ip = argv[1];
uint16_t port = atoi(argv[2]);
UdpSocket sock;
CHECK_RET(sock.Socket());
CHECK_RET(sock.Bind(ip, port));
while(1) {
std::string buf;
struct sockaddr_in cli_addr;
sock.Recv(buf, &cli_addr);
printf("client say:%s\n", buf.c_str());
std::cout<<"server say:";
fflush(stdout);
std::cin >> buf;
sock.Send(buf, cli_addr);
}
sock.Close();
return 0;
}
客户端:
#include "udpsocket.hpp"
int main (int argc, char *argv[])
{
if (argc != 3){
printf("./udp_cli ip port\n");
return -1;
}
std::string ip = argv[1];
uint16_t port = atoi(argv[2]);
struct sockaddr_in srv_addr;
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(port);
srv_addr.sin_addr.s_addr = inet_addr(ip.c_str());
UdpSocket sock;
CHECK_RET(sock.Socket());
while(1){
std::string buf;
std::cout<<"client say:";
fflush(stdout);
std::cin>>buf;
sock.Send(buf, srv_addr);
buf.clear();
sock.Recv(buf);
std::cout<<"server say:"<<buf<<std::endl;
}
sock.Close();
return 0;
}