gpt4 book ai didi

c++ - 从未调用过 WSASend 完成例程

转载 作者:行者123 更新时间:2023-11-28 02:26:41 40 4
gpt4 key购买 nike

我正在研究 Overlapped IO,突然发现似乎我是唯一一个不能鼓励 Completion callback 工作的人(所有声明都是关于:它工作但我不喜欢它) .

我的应用程序的想法是:客户端(telnet localhost 27015)连接到服务器,服务器开始向客户端推送大量数据。而且我从未调用过 CompletionCallback。

代码如下:

#include <winsock2.h>
#include <ws2tcpip.h>
#include <atomic>

#pragma comment(lib, "ws2_32.lib")
#define DATA_BUFSIZE 16384

class CSync
{
private:
CRITICAL_SECTION m_cs;

public:
CSync() { ZeroMemory(&m_cs, sizeof(m_cs)); InitializeCriticalSection(&m_cs); }
~CSync() { DeleteCriticalSection(&m_cs); ZeroMemory(&m_cs, sizeof(m_cs)); }
inline void Lock() { EnterCriticalSection(&m_cs); }
inline void Unlock() { LeaveCriticalSection(&m_cs); }
inline BOOL WINAPI TryLock() { return TryEnterCriticalSection(&m_cs); }
};

class ScopedLock
{
public:
ScopedLock(CSync& lock) : m_lock(lock) { m_lock.Lock(); }
~ScopedLock() { m_lock.Unlock(); }

private:
CSync m_lock;
};


class SendServer
{
private:
SOCKET socket;
// std::atomic<bool> busy;
char buffer[2][DATA_BUFSIZE];
CSync syncer;
WSABUF wsabuf;
OVERLAPPED overlapped;
// HANDLE socketEvent;
std::atomic_flag busy;
char toBuffer; // 0 or 1
DWORD sent;

public:
SendServer(SOCKET& sock);
virtual ~SendServer();
bool Write(char* buff);
};


static void __stdcall Produce(SendServer *server);
void CALLBACK CompletionCallback(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);



static bool run = 1;

int main(int argc, char* argv[])
{
WSADATA wsd;

struct addrinfo *result = NULL;
struct addrinfo hints;

SOCKET ListenSocket = INVALID_SOCKET;
SOCKET AcceptSocket = INVALID_SOCKET;

int err = 0;
int rc;

// Load Winsock
rc = WSAStartup((2, 2), &wsd);
if (rc != 0) {
printf("Unable to load Winsock: %d\n", rc);
return 1;
}

// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID)& hints, sizeof(struct addrinfo));

// Initialize the hints to obtain the
// wildcard bind address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

rc = getaddrinfo(NULL, "27015", &hints, &result);
if (rc != 0) {
printf("getaddrinfo failed with error: %d\n", rc);
return 1;
}

ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
//socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
return 1;
}

rc = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (rc == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}

rc = listen(ListenSocket, 1);
if (rc == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}
// Accept an incoming connection request
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
return 1;
}

printf("Client Accepted...\n");

SendServer server(AcceptSocket);
HANDLE h[1];

h[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&Produce, &server, 0, NULL);

getchar();
run = 0;
WaitForMultipleObjects(1, h, TRUE, INFINITE);

return 0;
}

void __stdcall Produce(SendServer *server)
{
char buf[] = "------------------------------------------------------------------------------------------";
char s = 0;

while (run) {
buf[0] = '0' + s++;

if (s > 9)
s = 0;

server->Write(buf);
Sleep(10);
}
}

void CALLBACK CompletionCallback(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
((SendServer*)(lpOverlapped->hEvent))->Write(NULL);
}

SendServer::SendServer(SOCKET& sock) : toBuffer(0)
{
socket = sock;
ZeroMemory(buffer, DATA_BUFSIZE << 1);
busy.clear();
}

SendServer::~SendServer()
{
shutdown(socket, 2);
closesocket(socket);
}

bool SendServer::Write(char* buff)
{
ScopedLock lock(syncer);
int size = strlen(buffer[toBuffer]), toAdd = 0;

if (buff == NULL) {
busy.clear();
SecureZeroMemory(buffer[!toBuffer], DATA_BUFSIZE);
}
else {
toAdd = strlen(buff);
if (size + toAdd < DATA_BUFSIZE) {
memcpy_s(buffer[toBuffer] + size, toAdd, buff, toAdd);
size += toAdd;
buffer[toBuffer][size] = 0;
return TRUE;
}
else {
printf("\nCan't add anymore!\n");
}
}

if (size > 0 && !busy.test_and_set()) {
wsabuf.buf = (char*)buffer[toBuffer];
wsabuf.len = size;

SecureZeroMemory(&overlapped, sizeof OVERLAPPED);
overlapped.hEvent = this;

toBuffer = !toBuffer;
size = WSASend(socket, &wsabuf, 1, &sent, 0, &overlapped, CompletionCallback);
if (size == 0) {
//return Write(NULL);
}
if (WSA_IO_PENDING != WSAGetLastError()) {
return FALSE;
}
}
return TRUE;
}

谢谢。

最佳答案

alertable wait 期间调用完成回调.您没有可提醒的等待,因此完成回调会排队但永远没有机会运行。

WaitForMultipleObjects 更改为包含 WaitForMultipleObjectsEx 的循环,并将 Sleep 更改为 SleepEx,并传递 TRUE 作为 bAlertable 参数。

这在 the WSASend documentation 中有解释

The completion routine follows the same rules as stipulated for Windows file I/O completion routines. The completion routine will not be invoked until the thread is in an alertable wait state such as can occur when the function WSAWaitForMultipleEvents with the fAlertable parameter set to TRUE is invoked.

关于c++ - 从未调用过 WSASend 完成例程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30403193/

40 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com