关于完成端口的2个问题

borland_boy 2005-08-05 10:44:05
1.GetQueuedCompletionStatus返回后如何知道是接收到了数据还是发送出去了数据还是其他别的状态
2.WSASend发送数据后如何控制数据发送长度呢?发送完成后怎样知道发送了多少数据出去
是用LPWSABUF lpBuffers的LEN 及BUFFER来控制发送数据的长度吗?发送完毕后如何得到发送了多少出去呢?
int WSASend (

SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
);
...全文
211 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
borland_boy 2005-08-08
  • 打赏
  • 举报
回复
// Create a socket information structure to associate with the socket
// 建立一个 socket 信息结构与 socket 关联
if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,
sizeof(PER_HANDLE_DATA))) == NULL)
{
FrmMainMemoAdd("GlobalAlloc() failed with error: " + IntToStr(GetLastError()));
return;
}

// Associate the accepted socket with the original completion port.
// 将接受的 socket 与原始完成端口关联

FrmMainMemoAdd("Socket number " + IntToStr(Accept) + " connected\n");
PerHandleData->Socket = Accept;

if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,
0) == NULL)
{
FrmMainMemoAdd("CreateIoCompletionPort failed with error: " + IntToStr(GetLastError()));
return;
}

// Create per I/O socket information structure to associate with the
// WSARecv call below.
// 建立每个 I/O socket 信息结构,以和下面的 WSARecv 调用关联

if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
FrmMainMemoAdd("GlobalAlloc() failed with error: " + IntToStr(GetLastError()));
return;
}

ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->BytesSEND = 0;
PerIoData->BytesRECV = 0;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;

Flags = 0;
if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING){
FrmMainMemoAdd("WSARecv() failed with error: " + IntToStr(WSAGetLastError()));
return;
}
}
}
}
//---------------------------------------------------------------------------

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred; //实际接收字符数
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;

while(TRUE)
{

if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
{
FrmMainMemoAdd("GetQueuedCompletionStatus failed with error: " + IntToStr(GetLastError()));
return 0;
}


// First check to see if an error has occured on the socket and if so
// then close the socket and cleanup the SOCKET_INFORMATION structure
// associated with the socket.
// 首先检查看 socket 是否发生错误,如果有错,
// 就关闭 socket 并清除与 socket 相有关联的 SOCKET_INFORMATION 结构

if (BytesTransferred == 0)
{
FrmMainMemoAdd("Closing socket " + IntToStr(PerHandleData->Socket));

if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
FrmMainMemoAdd("closesocket() failed with error: " + IntToStr(WSAGetLastError()));
return 0;
}

GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}

// Check to see if the BytesRECV field equals zero. If this is so, then
// this means a WSARecv call just completed so update the BytesRECV field
// with the BytesTransferred value from the completed WSARecv() call.
//检查 BytesRECV 域(或说成员变量)是否等于 0 ,
//如果是,这意味着 WSARecv 调用已经完成
//因此更新了 BytesRECV 域为来自完成 WSARecv() 调用的 BytesTransferred 值。


if (PerIoData->BytesRECV == 0)
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
}

if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{

// Post another WSASend() request.
// Since WSASend() is not gauranteed to send all of the bytes requested,
// continue posting WSASend() calls until all received bytes are sent.
// 提交其它 WSASend() 请求。因为 WSASend() 不 gauranteed(忘了什么意思) 发送所有请求的字节,
// 需要继续提交 WSASend() 调用直到接收到的字节被发送。


ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;

// PerIoData->DataBuf.len = DATA_BUFSIZE;
// PerIoData->DataBuf.buf = PerIoData->Buffer;


if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
FrmMainMemoAdd("WSASend() failed with error: " + IntToStr(WSAGetLastError()));
return 0;
}
}
}
else
{
PerIoData->BytesRECV = 0;

// Now that there are no more bytes to send post another WSARecv() request.
// 现在没有更多字节发送提交给其它 WSARecv() 请求。

Flags = 0;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;

if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
FrmMainMemoAdd("WSARecv() failed with error: " + IntToStr(WSAGetLastError()));
return 0;
}
}
}
}
}
//---------------------------------------------------------------------------
代码就是这样的,请根据代码帮助我解释一下这个问题

另外:为什么调用CreateThread创建工作线程后马上调用CloseHandle(ThreadHandle);关掉了吗?
borland_boy 2005-08-08
  • 打赏
  • 举报
回复
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Main.h"
#include "TServiceThread.h"
#pragma package(smart_init)


#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma argsused
#pragma comment (lib,"WS2_32.lib")

const int PORT = 4005; //服务端口
const int DATA_BUFSIZE = 16*1024; //接收缓冲区16K字节

typedef struct
{
WSAOVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;


typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, *LPPER_HANDLE_DATA;


DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);

//---------------------------------------------------------------------------

__fastcall TServiceThread::TServiceThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------

void __fastcall FrmMainMemoAdd(String sMessage)
{
FrmMain->MemoLog->Lines->Add(sMessage);
}
//---------------------------------------------------------------------------

void __fastcall TServiceThread::Execute()
{
SOCKADDR_IN InternetAddr;
SOCKET Listen;
SOCKET Accept;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsaData;
DWORD Ret;

if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
FrmMainMemoAdd("WSAStartup failed with error " + IntToStr(Ret));
return;
}

// 创建一个完成端口 / Setup an I/O completion port.

if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
{
FrmMainMemoAdd( "CreateIoCompletionPort failed with error: " + IntToStr(GetLastError()));
return;
}

// 确定机器有多少个CPU / Determine how many processors are on the system.

GetSystemInfo(&SystemInfo);

// Create worker threads based on the number of processors available on the
// system. Create two worker threads for each processor.
//根据系统可用的CPU数量创建工作线程,每个CPU运行2个工作线程

for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2 + 2; i++)
{

HANDLE ThreadHandle;

// Create a server worker thread and pass the completion port to the thread.
// 创建一个工作者线程并通过完成端口连接它。
if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,
0, &ThreadID)) == NULL)
{
FrmMainMemoAdd("CreateThread() failed with error: " + IntToStr(GetLastError()));
return;
}

// 关闭线程句柄 / Close the thread handle

CloseHandle(ThreadHandle);
}

// Create a listening socket
// 创建一个监听套接字

if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
FrmMainMemoAdd("WSASocket() failed with error: " + IntToStr(WSAGetLastError()));
return;
}

InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);

if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
FrmMainMemoAdd("bind() failed with error: " + IntToStr(WSAGetLastError()));
return;
}

// Prepare socket for listening
// 准备好一个监听套接字

if (listen(Listen, 5) == SOCKET_ERROR)
{
FrmMainMemoAdd("listen() failed with error: " + IntToStr(WSAGetLastError()));
return;
}

// Accept connections and assign to the completion port.
// 将接受的 socket 与原始完成端口关联
while(TRUE)
{
if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR){
FrmMainMemoAdd("WSAAccept() failed with error: " + IntToStr(WSAGetLastError()));
return;
}

ringphone 2005-08-08
  • 打赏
  • 举报
回复
CreateThread成功后会返回一个HANDLE,用这个HANDLE可以对线程进行控制或查询状态,必须用CloseHandle关闭,否则就会资源泄露。如果不需要对线程进行控制或查询状态就可以在CreateThread成功后立即关闭,不影响线程运行的。
yexingren 2005-08-05
  • 打赏
  • 举报
回复
1 2 通过重叠结构里面的参数来判断 ,可以在重叠结构中 定义 bytesrecv 和 bytessend 变量

flashboy 2005-08-05
  • 打赏
  • 举报
回复
重叠结构就是OVERLAPPED, 一般自己都会在这个基础上继承自己的结构,来定义一些自定义信息,比如你第一个问题中提到的问题(描述是发还是收),这样当GetQueuedCompletionStatus返回时,你就可以从这个结构中知道了。 第2个问题楼上的已经回答了。
VCSQLVB 2005-08-05
  • 打赏
  • 举报
回复
通过重叠结构里面的参数来判断 ,
bytes
borland_boy 2005-08-05
  • 打赏
  • 举报
回复
不明白什么重叠结构?

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧