udp_server.h
#pragma once
#include <iostream>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
namespace ns_server
{
enum{
SOCKET_ERR=1,
BIND_ERR
};
const static uint16_t default_port = 8080;
class UdpServer
{
public:
UdpServer(std::string ip, uint16_t port = default_port): ip_(ip), port_(port)
{
std::cout << "server addr: " << ip << " : " << port_ << std::endl;
}
void InitServer()
{
// 1. 创建socket接口,打开网络文件
sock_ = socket(AF_INET, SOCK_DGRAM, 0);//int socket(int domain, int type, int protocol);domain是标识你是想要网络通信还是本地通信,type表示的是套接字的种类,创建成功返回文件描述符
//AF_INET标识生成网络通信套接字,SOCK_DGRAM提供的是数据报通信,SOCK_STREAM提供的是数据流通信,第三个参数标识采用协议,默认为0,由系统根据第二个参数type进行判定。
if(sock_ < 0)
{
std::cerr << "create socket error: " << strerror(errno) << std::endl;
exit(SOCKET_ERR);//直接终止该进程
}
std::cout << "create socket success: " << sock_ << std::endl; //该文件符在当前情况下一般是3
// 2. 给服务器指明IP地址和Port(填写sockaddr信息)
struct sockaddr_in local; // 这个 local 在哪里定义呢?用户空间的特定函数的栈帧上,不在内核中!我们需要通过bind将loacl设置内核当中
bzero(&local, sizeof(local));//void bzero(void *s, size_t n);将local变量直接清零
local.sin_family = AF_INET; //也可以写成PF_INET,标识网络间通信,也就是该结构体的前16个比特位
local.sin_port = htons(port_);//port_是端口号,端口号这个两字节的数据必须出现在网络当中,方便目标进程将消息发回来,而htons是为了是将主机字节序转换成网络字节序,使网络程序具有可移植性,使同样的c代码在大端和小段计算机编译后。
// inet_addr: 1,2
// 1. 字符串风格的IP地址,转换成为4字节int, "1.1.1.1" -> uint32_t -> 能不能强制类型转换呢?不能,这里要转化,强转并不改变数据二进制的构成,只是将数据类型做转换。
// 2. 需要将主机序列转化成为网络序列
local.sin_addr.s_addr = inet_addr(ip_.c_str());//in_addr_t inet_addr(const char *cp)是将一个点分十进制风格的字符串地址转换成int类型地址,同时也将主机序列转换成为了网络序列
if(bind(sock_, (struct sockaddr*)&local, sizeof(local)) < 0)//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen),第一个参数是套接字,第二个是一个通用的结构体类型,第三个参数第二个参数的实际长度;bind是把已经填充好的local套接字字段和文件字段进行绑定关联,从而称为网阔文件
{
std::cerr << "bind socket error: " << strerror(errno) << std::endl;
exit(BIND_ERR);
}
std::cout << "bind socket success: " << sock_ << std::endl;
}
void Start()
{
}
~UdpServer() {}
private:
int sock_;//关于套接字的文件描述符
uint16_t port_;
std::string ip_; // 此ip地址是字符串风格的,比如:"1.1.1.1"。后面要专门研究一下,后面要去掉这个ip
};
} // end NS_SERVER
udp_server.c
#include "udp_server.hpp"
#include <memory>
using namespace ns_server;
using namespace std;
int main()
{
unique_ptr<UdpServer> usvr(new UdpServer("1.1.1.1", 8082));
usvr->InitServer(); //服务器的初始化
usvr->Start();//启动服务器
return 0;
}