当与服务器的连接超过1个时,c++tcp服务器(windows操作系统)-recv()会延迟
c++ tcp server (windows OS) - recv() delays when there is more then 1 connection to the server
当我试图连接到只有一个客户端的服务器时,服务器上的recv()
函数不会延迟。
但是,当我启动客户端控制台超过1次(大约7次)时,在向服务器发送带有send()
功能的数据包后,会有大约2000毫秒的延迟,直到服务器将数据包打印到控制台中。
有没有任何解决方案不为每个客户端启动一个线程?(Windows限制每个进程的线程数)。
该代码是用Visual Studio 2008编译的,这是完整的服务器代码:
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>
struct sslv3
{
#define max_clients 1024
private:
int cClient;
public:
SOCKET fd;
int CurrentClient()
{
return cClient;
}
struct client
{
client()
{
Valid = false;
}
bool Valid;
DWORD ip;
WORD port;
char ipstr[33];
char portstr[33];
SOCKET fd;
void StrGen()
{
wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
wsprintf(portstr, "%d", port);
}
} clients[max_clients];
//
sslv3(bool server_client)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
cClient = 0;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
DWORD timeout = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
}
int Bind(WORD port)
{
int ret = 0;
sockaddr_in local;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(port);
if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
!= SOCKET_ERROR)
listen(fd, SOMAXCONN);
return ret;
}
int Accept()
{
SOCKET clientfd;
sockaddr_in client;
int addrlen = sizeof(client);
clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
if(clientfd == -1)
return -1;
clients[cClient].ip = client.sin_addr.S_un.S_addr;
clients[cClient].port = client.sin_port;
clients[cClient].StrGen();
clients[cClient].fd = clientfd;
clients[cClient].Valid = true;
//
DWORD timeout = 1;
setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
cClient++;
if(cClient >= max_clients)
{
cClient = 0;
return max_clients - 1;
}
return cClient - 1;
}
int Connect(char ip[], WORD port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
}
int Send(SOCKET sfd, void* buffer, int length)
{
return send(sfd, (char*)buffer, length, 0);
}
int Read(SOCKET sfd, void* buffer, int length)
{
return recv(sfd, (char*)buffer, length, 0);
}
};
sslv3 cssl(true);
DWORD WINAPI ReadThread(void* args)
{
while(true)
{
for(int j = 0; j <= cssl.CurrentClient(); j++)
{
if(cssl.clients[j].Valid)
{
char rpack[1024];
for(int i = 0; i < sizeof(rpack); i++)
rpack[i] = 0;
if(cssl.Read(cssl.clients[j].fd, rpack, sizeof(rpack)) > 0){
printf("%s:%s says: %sn", cssl.clients[j].ipstr, cssl.clients[j].portstr, rpack);
}
}
}
Sleep(1);
}
return TRUE;
}
int main()
{
cssl.Bind(1234);
CreateThread(0,0,ReadThread,0,0,0);
while(true)
{
Sleep(1);
int cid = cssl.Accept();
if(cid != -1){
printf("%s:%s connected!n", cssl.clients[cid].ipstr, cssl.clients[cid].portstr);
}
}
return 0;
}
以下是完整的客户端代码:
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
struct sslv3
{
#define max_clients 1024
private:
int cClient;
public:
SOCKET fd;
int CurrentClient()
{
return cClient;
}
struct client
{
client()
{
Valid = false;
}
bool Valid;
DWORD ip;
WORD port;
char ipstr[33];
char portstr[33];
SOCKET fd;
void StrGen()
{
wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
wsprintf(portstr, "%d", port);
}
} clients[max_clients];
//
sslv3(bool server_client)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
cClient = 0;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
DWORD timeout = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
}
int Bind(WORD port)
{
int ret = 0;
sockaddr_in local;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(port);
if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
!= SOCKET_ERROR)
listen(fd, SOMAXCONN);
return ret;
}
int Accept()
{
SOCKET clientfd;
sockaddr_in client;
int addrlen = sizeof(client);
clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
if(clientfd == -1)
return -1;
clients[cClient].ip = client.sin_addr.S_un.S_addr;
clients[cClient].port = client.sin_port;
clients[cClient].StrGen();
clients[cClient].fd = clientfd;
clients[cClient].Valid = true;
//
DWORD timeout = 1;
setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
cClient++;
if(cClient >= max_clients)
{
cClient = 0;
return max_clients - 1;
}
return cClient - 1;
}
int Connect(char ip[], WORD port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
}
int Send(SOCKET sfd, void* buffer, int length)
{
return send(sfd, (char*)buffer, length, 0);
}
int Read(SOCKET sfd, void* buffer, int length)
{
return recv(sfd, (char*)buffer, length, 0);
}
};
sslv3 cssl(false);
int main()
{
cssl.Connect("127.0.0.1", 1234);
while(true)
{
printf("say: ");
char buf[1024];
for(int i = 0; i < sizeof(buf); i++)
buf[i] = 0;
cin >> buf;
int len = strlen(buf);
cssl.Send(cssl.fd, buf, len);
}
return 0;
}
服务器似乎"空闲"了2秒,因为一些客户端在2个sleep
秒后处理,每个客户端1秒。
这显然不是在服务器上处理多个客户端的正确方法。您可能需要查看select()
-参考。
一个非常好的套接字编程教程是Beej的
相关文章:
- "unknown ca"自生成的 CA、证书和客户端/服务器
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 如何通过套接字将文本文件的内容从服务器发送到客户端
- 有没有办法知道Tracer是否成功地完全连接到了jaegerclientcpp中的jaeger后端服务器
- 从服务器传输到客户端的消息不会出现
- QTcpSocket在不阻塞GUI的情况下重新连接到服务器
- OpenSSL TLS服务器-使用客户端证书白名单
- 在C++中设置基于操作系统的文件路径
- 我正在开发服务器,ip作为参数传递不起作用
- 我可以与 python 服务器而不是 c++ 客户端建立 tcp/ip 套接字吗?
- 提升 Asio TCP 服务器 处理多个客户端
- 如何在 Minecraft 服务器上执行命令
- 调试编译的服务器在数据库打开时崩溃
- C++套接字客户端到 Python 服务器未创建连接
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 将相机数据从服务器实时流式传输到客户端
- 为什么创建服务器后C++ httplib 库阻塞了我的主线程?
- 每个服务器请求的内存预算
- 当与服务器的连接超过1个时,c++tcp服务器(windows操作系统)-recv()会延迟
- 操作系统中的 TCP 服务器差异