18,356
社区成员
发帖
与我相关
我的任务
分享
局域网内两机收发包用boost::asio延迟在1ms左右。
如果只用RAW socket的同步收发,就是发一个包然后就收一个返回,延迟在300us左右。
但是,现在把收包和发包分在两个线程,延迟就到了好几毫秒,为什么?
#include <time.h>
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "../../test_socket1/test.h"
Record send_buffer[NUM*2];
Record recv_buffer[NUM*2];
//时间基线
static long long base = -1;
class Client
{
public:
Client()
{
//SOCKET前的一些检查,检查协议库的版本,为了避免别的版本的socket,并且通过
//WSAStartup启动对应的版本,WSAStartup的参数一个是版本信息,一个是一些详细的细节,注意高低位
//WSAStartup与WSACleanup对应
int err;
WORD versionRequired;
WSADATA wsaData;
versionRequired = MAKEWORD(1, 1);
err = WSAStartup(versionRequired, &wsaData);//协议库的版本信息
//通过WSACleanup的返回值来确定socket协议是否启动
if (!err)
{
printf("客户端嵌套字已经打开:%s:%d %d %d!\n", SERVER, PORT, NUM, sizeof(Record));
}
else
{
printf("客户端的嵌套字打开失败!\n");
//return 0;//结束
}
}
~Client()
{
//关闭套接字
closesocket(sock);
//关闭服务
WSACleanup();
}
void Connect(const char * ip, int port)
{
//创建socket这个关键词,这里想一下那个图形中的socket抽象层
//注意socket这个函数,他三个参数定义了socket的所处的系统,socket的类型,以及一些其他信息
sock = socket(AF_INET, SOCK_STREAM, 0);
int opt_val;
int opt_len = sizeof(opt_val);
if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&opt_val, &opt_len) == SOCKET_ERROR)
printf("ERROR: getsockopt SO_SNDBUF\n");
else
printf("getsockopt SO_SNDBUF:%d\n", opt_val);
if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&opt_val, &opt_len) == SOCKET_ERROR)
printf("ERROR: getsockopt SO_RCVBUF\n");
else
printf("getsockopt SO_RCVBUF:%d\n", opt_val);
if (getsockopt(sock, SOL_SOCKET, SO_SNDLOWAT, (char *)&opt_val, &opt_len) == SOCKET_ERROR)
printf("ERROR: getsockopt SO_SNDLOWAT\n");
else
printf("getsockopt SO_SNDLOWAT%d\n", opt_val);
if (getsockopt(sock, SOL_SOCKET, SO_RCVLOWAT, (char *)&opt_val, &opt_len) == SOCKET_ERROR)
printf("ERROR: getsockopt SO_RCVLOWAT\n");
else
printf("getsockopt SO_RCVLOWAT%d\n", opt_val);
int yes = 1;
if (setsockopt(sock, IPPROTO_TCP,TCP_NODELAY,(char*)&yes,sizeof(int)) == SOCKET_ERROR)
printf("ERROR: setsockopt TCP_NODELAY\n");
else
printf("setsockopt TCP_NODELAY%d\n", yes);
//socket编程中,它定义了一个结构体SOCKADDR_IN来存计算机的一些信息,像socket的系统,
//端口号,ip地址等信息,这里存储的是服务器端的计算机的信息
SOCKADDR_IN clientsock_in;
clientsock_in.sin_addr.S_un.S_addr = inet_addr(ip);
clientsock_in.sin_family = AF_INET;
clientsock_in.sin_port = htons(port);
//前期定义了套接字,定义了服务器端的计算机的一些信息存储在clientsock_in中,
//准备工作完成后,然后开始将这个套接字链接到远程的计算机
//也就是第一次握手
connect(sock, (SOCKADDR*)&clientsock_in, sizeof(SOCKADDR));//开始连接
}
void Start()
{
thd_send = std::thread(std::bind(&Client::Thread_Send, this));
thd_recv = std::thread(std::bind(&Client::Thread_Recv, this));
}
void SendData(const char * data, int len)
{
memcpy(send_buffer + send_pos, data, len);
send_pos++;
}
void OnRecv(const char * data, int len)
{
((Record *)data)->acked = GetSysTimeMicros() - base; //((Record *)data)->ref * 102;
}
private:
void Thread_Recv()
{
printf("Thread_Recv: %lld\n", GetSysTimeMicros() - base);
int recv_pos = 0;
while (true)
{
int n = recv(sock, (char *)(recv_buffer + recv_pos), sizeof(Record), 0);
if (n < 0)
break;
//printf("%d-%d recv\n", recv_pos, recv_buffer[recv_pos].ref);
OnRecv((char *)(recv_buffer + recv_pos), sizeof (Record));
recv_pos++;
if (recv_pos > NUM)
break;
}
}
void Thread_Send()
{
printf("Thread_Send: %lld\n", GetSysTimeMicros() - base);
int i = 0;
while (true)
{
if (i >= NUM)
break;
if (i < send_pos)
{
send_buffer[i].sent = GetSysTimeMicros() - base;
int n = send(sock, (char *)(send_buffer + i), sizeof(Record), 0);
if (n > 0)
{
//printf("%d-%d sent\n", i, send_buffer[i].ref);
i++;
}
else
{
printf("send error:%d\n", WSAGetLastError());
}
}
else
{
std::this_thread::sleep_for(std::chrono::microseconds(1));
printf("sleep 1 us after %d\n", i);
}
}
}
private:
SOCKET sock;
std::thread thd_send;
std::thread thd_recv;
std::atomic<int> send_pos = 0;
};
int main()
{
base = GetSysTimeMicros();
printf("main base: %lld\n", base);
Client * client = new Client;
client->Connect(SERVER, PORT);
client->Start();
Sleep(30); //必须要sleep,否则上面Start里的两个线程还没启动,但是下面的SendData已经给数据打开始的点了;Sleep之后,上面的两个线程也就启动了
Record data_send;
time_t start = time(nullptr);
for (int i = 0; i < NUM; i++)
{
data_send.ref = i;
data_send.put = GetSysTimeMicros() - base;// i * 100;
client->SendData((char *)(&data_send), sizeof (Record));
}
time_t end = time(nullptr);
printf("%d processed %d seconds\n", NUM, end-start);
getchar();
double total = 0;
printf("recv send ack-sent sent-put put send ack\n");
for (int i = 0; i < NUM; i++)
{
int t1 = recv_buffer[i].acked - send_buffer[i].sent;
total += t1;
int t2 = recv_buffer[i].sent - send_buffer[i].put;
printf("%3d %3d %8d %8d %lld %lld %lld\n", recv_buffer[i].ref, send_buffer[i].ref, t1, t2, recv_buffer[i].put, recv_buffer[i].sent, recv_buffer[i].acked);
}
printf("total %.2f\t avg: %.2fus\n", total, total*1.0 / NUM);
getchar();
return 0;
}