前言
针对客户端发送频率过高而服务端不能及时有效处理的情况。结合自己的实际测试给出以下处理方法。
一、socket服务端的建立
首先对客户端进行绑定(bind)监听(listen):
// created socket
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; // ipv4地址
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 任意地址
serv_addr.sin_port = htons(123); // 端口
if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0) {
std:cout << "bind failed!!!" << endl;
// 异常退出
exit(0);
}
// 进入监听状态,等待客户发起请求
if (listen(serv_sock, 20) != 0) {
std::cout << "Listen failed!!!" << endl;
close(serv_sock);
// 异常退出
exit(0);
}
二、扫描端口等待客户端连接
由于需要一直监听客户端状态整个扫描过程是while(true)循环过程:
while (true) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sockfd = accept(serv_sock, (struct sockaddr*)&client_addr, &client_len);
thread thread_test = thread([&]() { Dealing(client_sockfd, client_addr); });
thread_test.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
当客户端连接后通过Dealing函数与服务端进行数据交互。
三、全部数据获取、存储
void Dealing(const int client_sockfd, const struct sockaddr_in& client_addr) {
std::cout << "socket client: " << inet_ntoa(client_addr.sin_addr) << " has connnected!!!";
char socket_message[BYTE_LENGTH];
std::vector<char> buffer;
int length = 0;
int size;
while (true) {
memset(socket_message, 0, sizeof(socket_message));
int rev = recv(client_sockfd, socket_message, sizeof(socket_message), 0);
if (rev <= 0) {
std::cout << "socket receve rev = " << rev << endl;
break;
}
std::cout << "socket receve iret = " << rev << endl;
buffer.insert(buffer.end(), socket_message, socket_message + rev);
std::cout << "socket data buffer size is: " << buffer.size() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
close(client_sockfd);
将接收的数据放入vector容器这个数据缓存区。
四、容器暂存数据处理
bool CompleteFrame(vector<char>& buffer, int& length) {
// header length
if (buffer.size() < HEADERSIZE) {
return false;
}
vector<char>::iterator it = buffer.begin();
while (buffer.size() >= SIZE) {
// 帧头检验
if (*(it) == 0x12) {
// 根据数据帧提取数据长度
length = ToInt(buffer[2], buffer[3]);
return buffer.size() >= (HEADERSIZE + length);
} else {
// 对容器头部不为帧头信息的字段逐一进行清除
it = buffer.erase(it);
}
}
return false;
}
通过容器暂存数据,逐一遍历容器每个数据依据具体的协议信息提取出每一帧的数据,然后即可依据相应协议进行解析处理。