给别人做网站需要什么许可证,海口企业自助建站系统,国外物流公司网站模板,网站建设案例模板TCP socket心跳包示例程序_xqhrs232的专栏-CSDN博客_setsockopt 心跳包
原文地址::TCP socket心跳包示例程序_神奕的专栏-CSDN博客_tcp心跳包 相关文章
1、Linux网络编程--服务端判断客户端断开的经验方法 ----Linux网络编程--服务端判断客户端断开的经验方法_志存高远-CSDN博…TCP socket心跳包示例程序_xqhrs232的专栏-CSDN博客_setsockopt 心跳包
原文地址::TCP socket心跳包示例程序_神奕的专栏-CSDN博客_tcp心跳包 相关文章
1、Linux网络编程--服务端判断客户端断开的经验方法 ----Linux网络编程--服务端判断客户端断开的经验方法_志存高远-CSDN博客_info.tcpi_state
2、Socket心跳包机制及SO_KEEPALIVE套接口选项----Socket心跳包机制及SO_KEEPALIVE套接口选项_u012252959的博客-CSDN博客
3、TCP Keepalive HOWTO----TCP Keepalive HOWTO 在做游戏开发时经常需要在应用层实现自己的心跳机制即定时发送一个自定义的结构体心跳包让对方知道自己还活着以确保连接的有效性。
在TCP socket心跳机制中心跳包可以由服务器发送给客户端也可以由客户端发送给服务器不过比较起来前者开销可能更大。—— 这里实现的是由客户端给服务器发送心跳包基本思路是
1 服务器为每个客户端保存了IP和计数器count即mapfd, pairip, count。服务端主线程采用 select 实现多路IO复用监听新连接以及接受数据包心跳包子线程用于检测心跳
如果主线程接收到的是心跳包将该客户端对应的计数器 count 清零在子线程中每隔3秒遍历一次所有客户端的计数器 count 若 count 小于 5将 count 计数器加 1若 count 等于 5说明已经15秒未收到该用户心跳包判定该用户已经掉线
2 客户端则只是开辟子线程定时给服务器发送心跳包本示例中定时时间为3秒。 下面是Linux下一个socket心跳包的简单实现
/************************************************************************* File Name: Server.cpp Author: SongLee E-mail: lisong.shineqq.com Created Time: 2016年05月05日 星期四 22时50分23秒 Personal Blog: http://songlee24.github.io/************************************************************************/
#includenetinet/in.h // sockaddr_in
#includesys/types.h // socket
#includesys/socket.h // socket
#includearpa/inet.h
#includeunistd.h
#includesys/select.h // select
#includesys/ioctl.h
#includesys/time.h
#includeiostream
#includevector
#includemap
#includestring
#includecstdlib
#includecstdio
#includecstring
using namespace std;
#define BUFFER_SIZE 1024enum Type {HEART, OTHER};struct PACKET_HEAD
{Type type;int length;
};void* heart_handler(void* arg);class Server
{
private:struct sockaddr_in server_addr;socklen_t server_addr_len;int listen_fd; // 监听的fdint max_fd; // 最大的fdfd_set master_set; // 所有fd集合包括监听fd和客户端fd fd_set working_set; // 工作集合struct timeval timeout;mapint, pairstring, int mmap; // 记录连接的客户端fd--ip, count
public:Server(int port);~Server();void Bind();void Listen(int queue_len 20);void Accept();void Run();void Recv(int nums);friend void* heart_handler(void* arg);
};Server::Server(int port)
{bzero(server_addr, sizeof(server_addr));server_addr.sin_family AF_INET;server_addr.sin_addr.s_addr htons(INADDR_ANY);server_addr.sin_port htons(port);// create socket to listenlisten_fd socket(PF_INET, SOCK_STREAM, 0);if(listen_fd 0){cout Create Socket Failed!;exit(1);}int opt 1;setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt));
}Server::~Server()
{for(int fd0; fdmax_fd; fd){if(FD_ISSET(fd, master_set)){close(fd);}}
}void Server::Bind()
{if(-1 (bind(listen_fd, (struct sockaddr*)server_addr, sizeof(server_addr)))){cout Server Bind Failed!;exit(1);}cout Bind Successfully.\n;
}void Server::Listen(int queue_len)
{if(-1 listen(listen_fd, queue_len)){cout Server Listen Failed!;exit(1);}cout Listen Successfully.\n;
}void Server::Accept()
{struct sockaddr_in client_addr;socklen_t client_addr_len sizeof(client_addr);int new_fd accept(listen_fd, (struct sockaddr*)client_addr, client_addr_len);if(new_fd 0){cout Server Accept Failed!;exit(1);}string ip(inet_ntoa(client_addr.sin_addr)); // 获取客户端IPcout ip new connection was accepted.\n;mmap.insert(make_pair(new_fd, make_pair(ip, 0)));// 将新建立的连接的fd加入master_setFD_SET(new_fd, master_set);if(new_fd max_fd){max_fd new_fd;}
} void Server::Recv(int nums)
{for(int fd0; fdmax_fd; fd){if(FD_ISSET(fd, working_set)){bool close_conn false; // 标记当前连接是否断开了PACKET_HEAD head;recv(fd, head, sizeof(head), 0); // 先接受包头if(head.type HEART){mmap[fd].second 0; // 每次收到心跳包count置0cout Received heart-beat from client.\n;}else{// 数据包通过head.length确认数据包长度 } if(close_conn) // 当前这个连接有问题关闭它{close(fd);FD_CLR(fd, master_set);if(fd max_fd) // 需要更新max_fd;{while(FD_ISSET(max_fd, master_set) false)--max_fd;}}}}
}void Server::Run()
{pthread_t id; // 创建心跳检测线程int ret pthread_create(id, NULL, heart_handler, (void*)this);if(ret ! 0){cout Can not create heart-beat checking thread.\n;}max_fd listen_fd; // 初始化max_fdFD_ZERO(master_set);FD_SET(listen_fd, master_set); // 添加监听fdwhile(1){FD_ZERO(working_set);memcpy(working_set, master_set, sizeof(master_set));timeout.tv_sec 30;timeout.tv_usec 0;int nums select(max_fd1, working_set, NULL, NULL, timeout);if(nums 0){cout select() error!;exit(1);}if(nums 0){//cout select() is timeout!;continue;}if(FD_ISSET(listen_fd, working_set))Accept(); // 有新的客户端请求elseRecv(nums); // 接收客户端的消息}
}// thread function
void* heart_handler(void* arg)
{cout The heartbeat checking thread started.\n;Server* s (Server*)arg;while(1){mapint, pairstring, int ::iterator it s-mmap.begin();for( ; it!s-mmap.end(); ){ if(it-second.second 5) // 3s*5没有收到心跳包判定客户端掉线{cout The client it-second.first has be offline.\n;int fd it-first;close(fd); // 关闭该连接FD_CLR(fd, s-master_set);if(fd s-max_fd) // 需要更新max_fd;{while(FD_ISSET(s-max_fd, s-master_set) false)s-max_fd--;}s-mmap.erase(it); // 从map中移除该记录}else if(it-second.second 5 it-second.second 0){it-second.second 1;it;}else{it;}}sleep(3); // 定时三秒}
}int main()
{Server server(15000);server.Bind();server.Listen();server.Run();return 0;
}/************************************************************************* File Name: Client.cpp Author: SongLee E-mail: lisong.shineqq.com Created Time: 2016年05月05日 星期四 23时41分56秒 Personal Blog: http://songlee24.github.io/************************************************************************/
#includenetinet/in.h // sockaddr_in
#includesys/types.h // socket
#includesys/socket.h // socket
#includearpa/inet.h
#includesys/ioctl.h
#includeunistd.h
#includeiostream
#includestring
#includecstdlib
#includecstdio
#includecstring
using namespace std;
#define BUFFER_SIZE 1024enum Type {HEART, OTHER};struct PACKET_HEAD
{Type type;int length;
};void* send_heart(void* arg); class Client
{
private:struct sockaddr_in server_addr;socklen_t server_addr_len;int fd;
public:Client(string ip, int port);~Client();void Connect();void Run();friend void* send_heart(void* arg);
};Client::Client(string ip, int port)
{bzero(server_addr, sizeof(server_addr));server_addr.sin_family AF_INET;if(inet_pton(AF_INET, ip.c_str(), server_addr.sin_addr) 0){cout Server IP Address Error!;exit(1);}server_addr.sin_port htons(port);server_addr_len sizeof(server_addr);// create socketfd socket(AF_INET, SOCK_STREAM, 0);if(fd 0){cout Create Socket Failed!;exit(1);}
}Client::~Client()
{close(fd);
}void Client::Connect()
{cout Connecting...... endl;if(connect(fd, (struct sockaddr*)server_addr, server_addr_len) 0){cout Can not Connect to Server IP!;exit(1);}cout Connect to Server successfully. endl;
}void Client::Run()
{pthread_t id;int ret pthread_create(id, NULL, send_heart, (void*)this);if(ret ! 0){cout Can not create thread!;exit(1);}
}// thread function
void* send_heart(void* arg)
{cout The heartbeat sending thread started.\n;Client* c (Client*)arg;int count 0; // 测试while(1) {PACKET_HEAD head;head.type HEART;head.length 0; send(c-fd, head, sizeof(head), 0);sleep(3); // 定时3秒count; // 测试发送15次心跳包就停止发送if(count 15)break;}
}int main()
{Client client(127.0.0.1, 15000);client.Connect();client.Run();while(1){string msg;getline(cin, msg);if(msg exit)break;cout msg\n;}return 0;
}可以看出客户端启动以后发送了15次心跳包然后停止发送心跳包。在经过一段时间后3s*5服务器就判断该客户端掉线并断开了连接。