当前位置: 首页 > news >正文

TCP simultaneous open测试

源代码

/*************************************************************************> File Name: common.h> Author: hsz> Brief:> Created Time: 2024年10月23日 星期三 09时47分51秒************************************************************************/#pragma once#include <stdio.h>
#include <string.h>
#include <errno.h>#include <memory>#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>struct PeerMessage
{uint16_t    is_server;char        host[32];uint16_t    port;
};auto size = sizeof(PeerMessage);bool ReusePortAddr(int32_t sock, int32_t reuse = 1)
{if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&reuse, sizeof(reuse))) {perror("setsockopt(SO_REUSEPORT) error");return false;}if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse))) {perror("setsockopt(SO_REUSEPORT) error");return false;}return true;
}bool TimeoutConnect(int32_t sockfd, sockaddr_in addr, uint32_t timeoutMS)
{int flags = fcntl(sockfd, F_GETFL, 0);if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {perror("fcntl error");}std::shared_ptr<void>(nullptr, [&](void *) {// 恢复套接字为阻塞模式fcntl(sockfd, F_SETFL, flags);});// 连接到目标地址int ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));if (ret < 0 && errno != EINPROGRESS) { // 连接失败且不是EINPROGRESS// EINPROGRESS 表示仍在进行连接printf("Failed to connect: [%d:%s]\n", errno, strerror(errno));return false;}// 在非阻塞模式下,需要使用 select() 或 epoll() 等函数来等待连接完成fd_set fdset;FD_ZERO(&fdset);FD_SET(sockfd, &fdset);struct timeval timeout;timeout.tv_sec = 1;timeout.tv_usec = 0;ret = select(sockfd + 1, nullptr, &fdset, nullptr, &timeout);if (ret < 0) {printf("Failed to select: [%d:%s]\n", errno, strerror(errno));return false;} else if (ret == 0) { // 超时了printf("Connection timed out\n");return false;} else {  // 连接成功或失败int valopt = -1;socklen_t optlen = sizeof(valopt);getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&valopt, &optlen);  // 获取连接结果if (valopt != 0) {  // 连接失败printf("Failed to connect: [%d:%s]\n", valopt, strerror(valopt));return false;}}return true;
}
/*************************************************************************> File Name: tcp_simultaneous_open.cc> Author: hsz> Brief:> Created Time: 2024年10月25日 星期五 15时35分09秒************************************************************************/#include <iostream>
#include <string>
#include <cstring>
#include <thread>
#include <map>
#include <vector>
#include <thread>
#include <functional>#include <getopt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>#include "common.h"#include <log/log.h>#define LOG_TAG "TCP simultaneous open"int32_t Bind(const char *local_host, uint16_t local_port)
{// 创建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {printf("socket error, errno: %d, errstr: %s\n", errno, strerror(errno));return -1;}int32_t flag = 1;if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (char*)&flag, sizeof(flag))) {perror("setsockopt(SO_REUSEPORT) error");close(sockfd);return -1;}sockaddr_in local_addr;memset(&local_addr, 0, sizeof(local_addr));local_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = inet_addr(local_host);local_addr.sin_port = htons(local_port);if (bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) {perror("bind error");close(sockfd);return -1;}return sockfd;
}void thread_func(int32_t sock, const char *peer_host, uint16_t peer_port)
{sockaddr_in remote_addr;memset(&remote_addr, 0, sizeof(remote_addr));remote_addr.sin_family = AF_INET;remote_addr.sin_addr.s_addr = inet_addr(peer_host);remote_addr.sin_port = htons(peer_port);if (peer_port == 12999) {usleep(10); // usleep(1000 * 1000);}LOGI("begin");if (TimeoutConnect(sock, remote_addr, 1000)) {send(sock, "hello", 6, 0);char buf[16] = { '\0' };recv(sock, buf, sizeof(buf), 0);LOGI("recv: %s", buf);}LOGI("end");
}int main(int argc, char **argv)
{const char *bind_host = "192.168.3.10";int32_t firstSock = Bind(bind_host, 12999);int32_t secondSock = Bind(bind_host, 13999);if (firstSock < 0 || secondSock < 0) {return 0;}std::thread th1(std::bind(&thread_func, firstSock, bind_host, 13999));std::thread th2(std::bind(&thread_func, secondSock, bind_host, 12999));th1.join();th2.join();return 0;
}
测试结果

概率正常连接
抓包结果

延迟测试

由于两个套接字是客户端性质,必须保证同时处于SYN-SENT状态。
流程梳理:客户端A (127.0.0.1:12999)、客户端B(127.0.0.1:13999)
1、A向B发送SYN,此时B必须处于SYN-SENT状态,否则就会因为是客户端性质而收到RST信号
2、A收到RST信号后进入CLOSED 状态,此时B在延迟1ms后发送SYN,将同样收到RST信号

延迟探测

经过多次测试,延迟 5 - 20 微秒的概率会增大,如tcpdump的图,12999发送SYN的时间点是16:19:20.330111
收到SYN-ACK的时间点是16:19:20.330134,间隔了 23 微秒

后话

以上测试仅限本地。
公网环境存在传输时间,如果同时发送理论上能连接上的概率更大

参考

http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-4.htm


http://www.mrgr.cn/news/58604.html

相关文章:

  • Newstar_week1_week2_wp
  • 基于LSTM-Transformer混合模型实现股票价格多变量时序预测(PyTorch版)
  • 【Unity】游戏UI中添加粒子特效导致穿层问题的解决
  • git 免密的方法
  • 新的Midjourney就是一个增强版的Photoshop,你现在可以轻松的用它换衣服、换发型了
  • 工具_Nginx
  • 【Linux系统】如何证明进程的独立性
  • Redis的RDB执行原理
  • [CSP-J 2023] 一元二次方程(模拟)
  • bitpoke- mysql-operator cluster
  • java 17天 TreeSet以及Collections
  • SSH 的 N 大黑科技玩法
  • LeetCode Hot 100:二分查找
  • Visual Studio中无法打开Qt中UI文件,简单快捷处理方法
  • Zookeeper客户端工具 Apache Curator 最佳实践
  • 10340 文本编辑器(vim)
  • Swift 是一种由苹果公司开发的强大而直观的编程语言,主要用于开发 iOS、macOS、watchOS 和 tvOS 等苹果平台的应用程序。
  • C++中如何使用文件系统路径
  • AcWing 89:a^b ← 快速幂
  • 136.只出现一次的数字
  • 【开源项目】经典开源项目数字孪生工地——开源工程及源码
  • fpga系列 HDL: 竞争和冒险 01
  • 计算机网络:网络层 —— IPv4 协议的表示方法及其编址方法
  • python 线程间通信用什么手段
  • 微软投资比特币:将总资产1%投资于BTC?股东投票决定最终结果!
  • 洛谷 P1060 [NOIP2006 普及组] 开心的金明