0.关注博主有更多知识
目录
1.UDP服务端
使用C、C++混编的方式在Linux环境下实现一个简单的UDP服务端。那么我们先看代码,然后逐步分析:
// udpServer.hpp
#pragma once
#include <string>
#include <iostream>
#include <strings.h>
#include <functional>
/*网络必要的头文件*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/*其他操作系统接口*/
#include <unistd.h>
namespace server
{
using namespace std;
enum {SOCKET_ERROR = 1,START_ERROR,BIND_ERROR};
typedef function<void(int,struct sockaddr_in &,string &)> func_t;
class udpServer
{
public:
/*服务器不需要绑定任何IP!
*绑定默认的0.0.0.0即可
*绑定了一个指定的IP之后,只能接收到指定IP的客户端的数据*/
udpServer(const func_t &func,const uint16_t &port,const string &ip = defaultIp)
:_func(func),_port(port),_ip(ip),_socketFd(-1)
{
/*以IP协议、数据报的形式打开文件
*也就是以UDP协议打开网络文件
*如果打开失败,说明无法进行网络通信,程序退出*/
_socketFd = socket(AF_INET,SOCK_DGRAM,0);
if(_socketFd == -1)
{
cerr << "socket fail" << endl;
exit(SOCKET_ERROR);
}
cout << "socket success: " << _socketFd << endl;
/*以后对网络的I/O的操作就是对网络文件操作
*但是还没有将该文件绑定IP和端口号,也就是还没有绑定套接字
*所以现在要绑定套接字*/
struct sockaddr_in local = getSockaddr_in();
int n = bind(_socketFd,(struct sockaddr *)&local,sizeof(local));
if(n == -1)
{
cerr << "bind fail" << endl;
exit(BIND_ERROR);
}
/*至此套接字创建工作完成*/
}
~udpServer()
{}
void start()
{
while(true)
{
/*读取客户端发送的数据
*并打印出来,相当于服务器后台日志*/
char buffer[buffer_num];
struct sockaddr_in client;
socklen_t len = sizeof(client);
int n = recvfrom(_socketFd,buffer,sizeof(buffer)-1,0,(struct sockaddr *)&client,&len);
if(n > 0)
{
buffer[n] = 0;
string message = buffer;
string clinetIp = inet_ntoa(client.sin_addr);
uint16_t clinetPort = ntohs(client.sin_port);
cout << clinetIp << "[" << clinetPort << "]# " << message << endl;
/*回调*/
_func(_socketFd,client,message);
}
}
}
private:
/*参与网络通信需要端口号和ip地址
*端口号是一个2字节的整数
*ip地址用点分十进制的字符串表示*/
uint16_t _port;
string _ip;
/*以文件的形式打开一个网络文件
*即使用socket()打开一个网络文件*/
int _socketFd;
/*所有对象共享一个默认的IP*/
static const string defaultIp;
static const int buffer_num = 1024;
/*回调函数:服务器要处理的业务逻辑*/
func_t _func;
/*获取struct sockaddr结构体*/
struct sockaddr_in getSockaddr_in()
{
struct sockaddr_in local;
/*初始化sockaddr_in对象
*并且将端口号、IP地址设置进去
*我们使用的IP地址是字符串,所以需要转换成整数
*使用inet_addr()接口,里面自动转换成整数,并且自动大小端字节序*/
bzero((void *)&local,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(_port);
//local.sin_addr.s_addr = inet_addr(_ip.c_str());
local.sin_addr.s_addr = INADDR_ANY;
return local;
}
};
const string udpServer::defaultIp = "0.0.0.0";
} /*namespace server ends here*/
首先我们介绍一下scoket()接口: