c++socket 心跳机制代码

server.h:

#pragma once
#include
#include
#include
#pragma comment (lib ,“ws2_32.lib”)

class server
{
public:
server();
~server();
void severStart(int port);
void serverStop();
void serverAccpt();
void serverRecv();
void selectHeart();
private:
SOCKET serverSide;
SOCKET clientSide;
std::map clientHeart;
};

server.cpp

#include “stdafx.h”
#include “server.h”
#include
#include
using namespace std;

server::server()
{
}

server::~server()
{
}

//启动服务器
void server::severStart(int port)
{
WSADATA wsa = { 0 };
WSAStartup(MAKEWORD(2, 2), &wsa); //使用函数WSAStartup()绑定相应版本的套接字库:成功返回0;

//创建套接字(参数为:)地址系列     套接字类型         协议号
//socket(domain = AF_INET, type = SOCK_STREAM, proto = IPPROTO_TCP)
serverSide = socket(AF_INET, SOCK_STREAM, 0);
//1.domain : Domain参数指定了通信的”域”  AF_UNIX:AF_LOCAL本地通信  AF_INET : IPv4网络通信  AF_INET6 : IPv6网络通信  AF_PACKET : 链路层通信
//2. Type: Type就是socket的类型,对于AF_INET协议族而言有流套接字(SOCK_STREAM)、数据包套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)

SOCKADDR_IN addr;  //地址集
addr.sin_family = AF_INET; // 设置地址族为IPV4
addr.sin_port = htons(port); // 设置地址的端口号信息
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 设置IP地址;

// bind() 服务端套接字绑定自己的IP地址与端口号,客户端那边可以不写,内核会给它分配一个临时的端口。
//参数:
//	1)、sockfd: 服务器或者客户端自己创建的socket
//	2)、sockaddr : 服务器或者客户端自己的地址信息(协议族、IP、端口号)
::bind(serverSide, (SOCKADDR *)&addr, sizeof(addr));
	// listen(int  sockfd, int  backlog);
//用法:函数应该在调用socket和bind这两个函数之后,accept函数之前调用。
//	作用:让服务器套接字sockfd进入监听状态。
//	参数:sockfd:套接字,成功返回后进入监听模式,当有新连接并accept后会再建立一个套接字保存新的连接;
//         backlog:并发连接数  backlog的取值范围 ,一般为0-5。
listen(serverSide, 5);
thread t1(&server::serverAccpt, this);
t1.detach();

}

void server::serverStop()
{
closesocket(serverSide);
cout << “服务端关闭” << endl;
WSACleanup();
}

//连接客户端
void server::serverAccpt()
{
//检测心跳
thread tt(&server::selectHeart, this);
tt.detach();
while (true)
{
SOCKADDR_IN clientAddr;
int len = sizeof(clientAddr);
//accept函数返回值是一个客户端和服务器连接的SOCKET类型的描述符,在服务器端标识着这个客户端。
clientSide = accept(serverSide, (SOCKADDR*)&clientAddr, &len);
if (clientSide == INVALID_ATOM)
{
cout << “无效连接” << endl;
}
char ip[32];
inet_ntop(AF_INET, &clientAddr.sin_addr, ip, sizeof(ip));
cout << “连接” << endl;
clientHeart[clientSide] = 5;
//收包
thread t1(&server::serverRecv,this);
t1.detach();
}
}

// 收报;
void server::serverRecv()
{
while (true)
{
char buff[1024] = {0};
// recv(socket s, char * buf, int len,intflag)
// 参数socket:创建的可以传输消息过来的套接字
// 参数buf:接受消息的字符串缓存
// 参数len:允许接收字符串的缓存的最大长度
// 第四个参数:会对函数行为产生影响,一般设置为0
// send和recv实际上分别是write和read函数的基础上扩展了第四个参数:
int res=recv(clientSide, buff, sizeof(buff), 0);
if (res<=0)
{
cout << “连接断开***” << endl;
break;
}
cout << res << endl;
clientHeart[clientSide] = 5;
}
}

// 心跳机制
void server::selectHeart()
{
cout << “进入心跳” << endl;
while (true)
{
for (auto iter=clientHeart.begin();iter!=clientHeart.end()?//条件判断放到else中判断;
{
iter->second = iter->second -1;
clientHeart[iter->first] = iter->second;
cout << iter->second << endl;
if (iter->second == 0)
{
cout << “客户端断开” << endl;
closesocket(clientSide);
clientHeart.erase(iter++);// iter++;删除到末尾时for循环中的iter++会指向后面不存在地址;程序崩;
if (iter == clientHeart.end())
{
cout << “到末尾” << endl;
break;
}
}
else
{
// 使用指针时,删除的话会跳一个,
iter++;
}
}
Sleep(3000); // 设置3秒发射一个信号判断;总计时为15秒;
}
}

mian.cpp

#include “stdafx.h”
#include “server.h”
#include
#include
using namespace std;

int main()
{
server s;
s.severStart(7777);
string cmd;
cin >> cmd;
if (cmd ==“exit”)
{
s.serverStop();
}
return 0;
}

你可能感兴趣的:(c++)