socket服务端在客户端高频发送情况下的接收处理

前言

针对客户端发送频率过高而服务端不能及时有效处理的情况。结合自己的实际测试给出以下处理方法。

一、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;
}

通过容器暂存数据,逐一遍历容器每个数据依据具体的协议信息提取出每一帧的数据,然后即可依据相应协议进行解析处理。

以下是Java中基于TCP协议的Socket通讯,发送接收16进制报文的代码示例: 服务端代码: ```java import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try { // 创建服务端Socket并绑定端口号 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务端已启动,等待客户端连接..."); // 等待客户端连接 Socket socket = serverSocket.accept(); System.out.println("客户端连接"); // 获取输入流 InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int len; // 循环读取数据 while ((len = inputStream.read(buffer)) != -1) { // 将字节数组转换为16进制字符串 String hexString = bytesToHexString(buffer, len); System.out.println("收到客户端消息:" + hexString); } // 关闭流和Socket inputStream.close(); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } // 将字节数组转换为16进制字符串 private static String bytesToHexString(byte[] bytes, int len) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { String hex = Integer.toHexString(bytes[i] & 0xff); if (hex.length() == 1) { sb.append("0"); } sb.append(hex.toUpperCase()); } return sb.toString(); } } ``` 客户端代码: ```java import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) { try { // 创建客户端Socket连接服务端 Socket socket = new Socket("127.0.0.1", 8888); // 获取输出流 OutputStream outputStream = socket.getOutputStream(); // 发送16进制报文 String hexString = "AABBCCDD"; byte[] bytes = hexStringToBytes(hexString); outputStream.write(bytes); // 关闭流和Socket outputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } // 将16进制字符串转换为字节数组 private static byte[] hexStringToBytes(String hexString) { int len = hexString.length() / 2; byte[] bytes = new byte[len]; for (int i = 0; i < len; i++) { bytes[i] = (byte) Integer.parseInt(hexString.substring(i * 2, i * 2 + 2), 16); } return bytes; } } ``` 以上代码示例中,服务端通过创建ServerSocket监听端口8888,等待客户端连接客户端通过创建Socket连接服务端,并获取输出流发送16进制报文。服务端通过获取输入流读取数据,并将字节数组转换为16进制字符串。客户端服务端均提供了将16进制字符串转换为字节数组和将字节数组转换为16进制字符串的方法,方便进行数据转换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值