【Linux】手把手教你实现udp服务器
网络套接字~
文章目录
- 前言
- 一、udp服务器的实现
- 总结
前言
上一篇文章中我们讲到了很多的网络名词以及相关知识,下面我们就直接进入udp服务器的实现。
一、udp服务器的实现
首先我们需要创建五个文件(文件名可以自己命名也可以和我一样),分别是makefile,udpclient.cc,udpclient.hpp,udpserver.cc,udpserver.hpp,下面我们先进行makefile的编写,在makefile中我们要一次创建两个可执行程序:
cc=g++ .PHONY:all all:udpClient udpServer udpClient:udpClient.cc $(cc) -o $@ $^ -std=c++11 udpServer:udpServer.cc $(cc) -o $@ $^ -std=c++11 .PHONY:clean clean: rm -f udpClient udpServer
我们通过all就可以创建多个可执行程序了,对于cc这个变量我们设置为g++,以后如果想换其他的编译器就可以直接替换了。
在udpserver.hpp这个文件中我们先写出整体框架:
namespace Server { class udpServer { public: udpServer() { } void InitServer() { } void start() { } ~udpServer() { } private: //服务器一定要有自己的服务端口号(注意端口号是16位的) uint16_t _port; //端口号 //实际上一款服务器不建议指明一个IP string _ip; //ip }; }
那么我们现在服务器的ip填多少呢?实际上我们只是完成测试,所以ip就填0.0.0.0就好了,这样的话任意的ip都能访问我们的服务器,所以我们定义一个static变量来保存ip:
static const string defaultIp = "0.0.0.0";
有了ip和端口号后,我们就可以用构造函数初始化了:
udpServer(const uint16_t& port,const string ip = defaultIp) :_port(port) ,_ip(ip) { }
我们的服务器未来要启动的话就必须先初始化然后再启动,所以我们写了init和start接口,那么该如何初始化呢?实际上不管是udp还是tcp,我们初始化都是需要套接字的,下面我们看看套接字的接口:
如何理解套接字呢,我们都知道linux一切皆文件,所以未来的网络通信一定是在同一个文件中只要和网卡设备关联起来就实现了网络通信,所以套接字的目的实际上是创建一个文件,可以看到我们的套接字有三个参数,第一个参数的解释是域,实际上就是让我们选择是进行网络通信还是本地通信,这里我们一般选择AF_INET选项,代表使用IPV4协议的网络通信。第二个参数是type,表面套接字要向我们提供服务的类型,怎么理解呢,如下图:
我们现在所写的UDP服务器的特点是不可靠传输无连接,而这正是与SOCK_DGRAM这个选项所匹配的,我们查看这个选项的解释可以看到:DGRAM适用于不可靠传输,连接少
我们下一篇要实现的TCP服务器,就会用到SOCK_STREAM这个选项,因为这个选项的解释是面向流式服务,而我们TCP的特点就是面向字节流。
第三个参数我们一般缺省为0,因为这个参数代表我们未来要采用什么协议,如果我们写为0,那么这个接口会根据我们填的前两个参数来帮我们确定第三个参数是选择TCP协议还是UDP协议。
这个接口的返回值相信大家也看到了,没错!一旦创建套接字成功,那么就会给我们返回一个文件描述符,如果失败则会给我们返回-1并且提供错误码。
了解了socket这个接口,那么我们下一步就是增加一个私有变量来接收socket返回的文件描述符(注意:这个文件描述符会被后面的接口多次用到):
然后我们在构造函数中将这个文件描述符初始化为-1:
udpServer(const uint16_t& port,const string ip = defaultIp) :_port(port) ,_ip(ip) ,_sockfd(-1) { }
然后我们初始化第一步:使用套接字
void InitServer() { //UDP第一步:创建了一个套接字 _sockfd = socket(AF_INET,SOCK_DGRAM,0); if (_sockfd==-1) { cerr