前言:
在网上找了很多Socket长连接的实现方式,但是自己拿过来用都有问题,为了解决这个问题,本人花了不少时间在上面。其实 socket 长连接很简单,就是连接后不断开即可。接下来,这里贴上实现的源码例子。本人做这个东西是为了在pc上运行的游戏,所以方法的实现是基于 window api 的,linux上的也大同小异。
另外,本人也是刚实现不久,例如:心跳这些还没有去实现。如果在文章中发现什么问题,欢迎各路大牛指正。
C++ 所需头文件:
#include <thread>
#include <functional>
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
首先就是C++代码 监听的代码(可以放到函数体内部):
// port 需要监听的端口
// listenCallback 一个客户端连接进入时,新建线程执行的方法
void ListenPort(unsigned short port, std::function<bool(SOCKET clientSocket)> listenCallback) {
// 初始化 WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0) {
std::cout << "WSAStartup error!" << std::endl;
return;
}
// 创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
std::cout << "create socket error!" << std::endl;
return;
}
// 绑定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(serverSocket, (LPSOCKADDR) &sin, sizeof(sin)) == SOCKET_ERROR) {
std::cout << "bind error" << std::endl;
return;
}
// 监听
if (listen(serverSocket, 5) == SOCKET_ERROR) {
std::cout << "listen error" << std::endl;
return;
}
// 等待客户端连接
SOCKET socketClient;
sockaddr_in remoteAddr;
int remoteAddrlen = sizeof(remoteAddr);
while (true) {
// 一个新的客户端连入
clientSocket = accept(serverSocket, (SOCKADDR *) &remoteAddr, &remoteAddrlen);
// 开启一个新的线程去给这个客户端发送消息
std::thread clientConnectThread = std::thread(listenCallback, clientSocket);
clientConnectThread.detach();
}
}
到这这里,只是建立了一个socket的监听而已,并没有实现长连接。其实,是否长连接。取决于是否关闭客户端的socket(代码中的:clientSocket),只要不关闭socketClient 就可以一直不断地发送消息到客户端了。
回调函数的例子:
// 每 500ms 向客户端发送一次 "hello" 消息(如果客户端一秒接受一次的话,可能会接收到连续的字符串,如客户端接收一次可能是:"hellohello",由两次send的发送结果)
std::function<bool(SOCKET clientSocket)> listenCallback = [](SOCKET clientSocket) {
while(true) {
const char * buff = "hello";
int len = strlen(buff);
send(clientSocket, buff, len, 0);
// 当前线程休眠 500ms
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
// 关闭客户端 socket
// closesocket(clientSocket);
};