提交 966c575e 编写于 作者: X xuchi

服务端升级为ipv6_001

上级 4d57c891
......@@ -24,24 +24,26 @@ namespace doyou {
private:
//
Thread _thread;
//消息处理对象,内部会创建线程
// 消息处理对象,内部会创建线程
std::vector<Server*> _cellServers;
//每秒消息计时
// 每秒消息计时
Timestamp _tTime;
// 服务端套接字,功能:接收新的客户端加入
SOCKET _sock;
protected:
// 服务端采用IPV协议版本,默认IPV4
int _address_family = AF_INET;
// 客户端发送缓冲区大小
int _nSendBuffSize;
// 客户端接收缓冲区大小
int _nRecvBuffSize;
// 客户端连接上限
int _nMaxClient;
//SOCKET recv计数
// SOCKET recv计数 原子操作(多线程数据保护)
std::atomic_int _recvCount;
//收到消息计数
std::atomic_int _msgCount;
// 收到消息计数
std::atomic_int _msgCount;
// (已连接)客户端计数 = 连接已分配总数 + 连接未分配总数
std::atomic_int _clientAccept;
// 已分配(给处理接收和发送网络消息线程)客户端计数
......@@ -64,7 +66,7 @@ namespace doyou {
Close();
}
// 初始化Socket(服务端程序)
SOCKET InitSocket()
SOCKET InitSocket(int af = AF_INET) // 参数默认值-IPV4
{
NetWork::Init();
if (INVALID_SOCKET != _sock)
......@@ -72,7 +74,9 @@ namespace doyou {
CELLLog_Warring("initSocket close old socket<%d>...", (int)_sock);
Close();
}
_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
_address_family = af;
_sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == _sock)
{
CELLLog_PError("create socket failed...");
......@@ -85,34 +89,51 @@ namespace doyou {
return _sock;
}
//绑定IP和端口号
// 绑定IP和端口号
int Bind(const char* ip, unsigned short port)
{
//if (INVALID_SOCKET == _sock)
//{
// InitSocket();
//}
// 2 bind 绑定用于接受客户端连接的网络端口
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(port);//host to net unsigned short
int ret = SOCKET_ERROR; // 编程建议:变量在声明同时进行初始化,避免可能的错误
if (AF_INET == _address_family) { // ipv4
sockaddr_in sin = {};
sin.sin_family = AF_INET;
sin.sin_port = htons(port); // host to net unsigned short
#ifdef _WIN32
if (ip){
_sin.sin_addr.S_un.S_addr = inet_addr(ip);
}
else {
_sin.sin_addr.S_un.S_addr = INADDR_ANY;
}
#ifdef _WIN32 // 采用宏来区分window和linux系统
if (ip){
sin.sin_addr.S_un.S_addr = inet_addr(ip);
}
else {
sin.sin_addr.S_un.S_addr = INADDR_ANY; // 本机任意IP
}
#else
if (ip) {
_sin.sin_addr.s_addr = inet_addr(ip);
if (ip) {
sin.sin_addr.s_addr = inet_addr(ip);
}
else {
sin.sin_addr.s_addr = INADDR_ANY;
}
#endif
ret = bind(_sock, (sockaddr*)&sin, sizeof(sin));
}
else {
_sin.sin_addr.s_addr = INADDR_ANY;
else if(AF_INET6 == _address_family) { // ipv6
sockaddr_in6 sin = {};
sin.sin6_family = AF_INET6;
sin.sin6_port = htons(port);
if (nullptr != ip) {
inet_pton(AF_INET6, ip, &sin.sin6_addr); // inet_pton函数在其标准文本呈现形式中将 IPv4 或 IPv6 Internet 网络地址转换为其数字二进制形式。// 将para2数值按照para1格式转换后存储到para3
}
else {
sin.sin6_addr = in6addr_any; // 没传入IP, 默认本机任意IP
}
ret = bind(_sock, (sockaddr*)&sin, sizeof(sin));
}
#endif
int ret = bind(_sock, (sockaddr*)&_sin, sizeof(_sin));
else {
CELLLog_Error("bind port failed, _address_family<%d>", _address_family);
return ret;
}
if (SOCKET_ERROR == ret)
{
// GetLastError(): windows系统获取错误时机的错误码,可在网上搜罗错误码的错误含义或者差错误手册
......@@ -122,6 +143,7 @@ namespace doyou {
else {
CELLLog_Info("bind port<%d> success...", port);
}
return ret;
}
......@@ -144,6 +166,61 @@ namespace doyou {
SOCKET Accept()
{
// 4 accept 等待接受客户端连接
if (AF_INET == _address_family) {
return Accept_Ipv4();
}
return Accept_Ipv6(); // 不是ipv4, 就是ipv6, 前面已经校验过
}
// 接受客户端连接-ipv6
SOCKET Accept_Ipv6()
{
sockaddr_in6 clientAddr = {};
int nAddrLen = sizeof(clientAddr);
SOCKET cSock = INVALID_SOCKET;
#ifdef _WIN32
cSock = accept(_sock, (sockaddr*)&clientAddr, &nAddrLen);
#else
cSock = accept(_sock, (sockaddr*)&clientAddr, (socklen_t *)&nAddrLen);
#endif
if (INVALID_SOCKET == cSock)
{
// errno-错误码 strerror-错误码对应描述信息
// 接收到的新客户端套接字无效
CELLLog_PError("accept INVALID_SOCKET...errno<%d> errMsg<%s>", errno, strerror(errno));
}
else
{
//CELLLog_Info("accept cSock<%d>", cSock);
// 客户端链接上限校验
if (_clientAccept < _nMaxClient)
{
_clientAccept++; // 连接的新客户端被分配给Server,计数+1
NetWork::make_reuseaddr(cSock);
// 将新客户端分配给客户数量最少的cellServer
addClientToCELLServer(new Client(cSock, _nSendBuffSize, _nRecvBuffSize));
// 获取IP地址 inet_ntoa(clientAddr.sin_addr)
}
else {
// 获取IP地址 inet_ntoa(clientAddr.sin_addr)
// 分析:超出链接上限,先链接再关闭:
// 好处1)可以知道是谁链接我们了(客户端信息)。
// 好处2)做一些其它操作,比如通知客户端我超限制了
// 好处3)可以查看该客户端是否在黑名单或白名单中,是否有传指定验证码token, 客户端需要传入一个正确的检验码。
// 如果重复多次链接,有可能是恶意链接。
NetWork::destroy_socket(cSock);
CELLLog_Warring("Accept to nMaxClient");
}
}
return cSock;
}
// 接受客户端连接-ipv4
SOCKET Accept_Ipv4()
{
sockaddr_in clientAddr = {};
int nAddrLen = sizeof(sockaddr_in);
SOCKET cSock = INVALID_SOCKET;
......@@ -173,7 +250,8 @@ namespace doyou {
else {
// 获取IP地址 inet_ntoa(clientAddr.sin_addr)
// 分析:超出链接上限,先链接再关闭:
// 好处1)可以知道是谁链接我们了(客户端信息)。好处2)做一些其它操作,比如通知客户端我超限制了
// 好处1)可以知道是谁链接我们了(客户端信息)。
// 好处2)做一些其它操作,比如通知客户端我超限制了
// 好处3)可以查看该客户端是否在黑名单或白名单中,是否有传指定验证码token, 客户端需要传入一个正确的检验码。
// 如果重复多次链接,有可能是恶意链接。
NetWork::destroy_socket(cSock);
......
......@@ -14,4 +14,6 @@
5.服务端和客户端要么同时用ipv4, 要么同时用ipv6, 混搭是不行的,比如ipv4客户端是不能链接ipv6服务端。
6.编码建议:函数太长了就要封装更小的函数,以避免代码冗余。建议函数上限30行。
......@@ -38,7 +38,10 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)../bin/$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)../tmp/$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册