“重叠I/O操作正在进行中”,为什么会出现这个错误!? ( 积分: 300 )

  • 主题发起人 主题发起人 寻路
  • 开始时间 开始时间

寻路

Unregistered / Unconfirmed
GUEST, unregistred user!
IOCP的操作,在WSARecv的时候就出现这个错误,郁闷:
unit IOCP;

interface
uses SysUtils, Classes, Windows, WinSock2, SocketExceptionCounts;

const
SERV_PORT = 9877;
DATA_BUFSIZE = 8192;
type
{
TCPOverlapped = record
Overlapped: _OVERLAPPED;
OVKey: Integer;
IsRead: Boolean;
Buffer: WSABUF;
SendingData: string;
end;
PCPOverlapped = ^TCPOverlapped;

//¹Ø¼üÏî
PER_IO_OPERATION_DATA = packed record
Overlapped: TOverlapped;
DataBuf: TWSABUF;
Buffer: array [0..DATA_BUFSIZE - 1] of Char;
BytesSEND: DWORD;
BytesRECV: DWORD;
end;
}
//¹Ø¼üÏî
PER_IO_OPERATION_DATA = packed record
Overlapped: TOverlapped;
DataBuf: TWSABUF;
Buffer: array [0..DATA_BUFSIZE - 1] of Char;
BytesSEND: DWORD;
BytesRECV: DWORD;
end;


LPPER_IO_OPERATION_DATA = ^PER_IO_OPERATION_DATA;

PER_HANDLE_DATA = packed record
Socket: TSocket;
end;

LPPER_HANDLE_DATA = ^PER_HANDLE_DATA;


ESocketError = class(Exception)
public
constructor Create(); overload;
public
property HelpContext;
property Message;
end;

TSimpleICOP = class(TObject)
private
FLocalSockHandle: TSocket;
FLocalSockAddrIn: TSockAddrIn;
FCompletionPort: THandle;
FSystemInfo: TSystemInfo;
FRemoteSockHandle: TSocket;

FPerHandleData: LPPER_HANDLE_DATA;
FPerIoData: LPPER_IO_OPERATION_DATA;
private
class procedure StartSocket();
class procedure StopSocket();
public
constructor Create;
procedure Free;
public
procedure InitSocket();
end;

function ServerWorkerThread(CompletionPortID: THandle): DWORD; stdcall;


implementation

function ServerWorkerThread(CompletionPortID: THandle): DWORD; stdcall;
var
CompletionPort: THandle;
BytesTransferred: DWORD;
PerHandleData: LPPER_HANDLE_DATA;
PerIoData: LPPER_IO_OPERATION_DATA;
SendBytes, RecvBytes, Flags: DWORD;
begin
CompletionPort := THandle(CompletionPortID);

while True do
begin
if GetQueuedCompletionStatus(CompletionPort, BytesTransferred,
DWORD(PerHandleData), POverlapped(PerIoData), INFINITE) = LongBool(0) then
raise ESocketError.Create();

if BytesTransferred = 0 then
begin
if closesocket(PerHandleData.Socket) = SOCKET_ERROR then raise ESocketError.Create();

GlobalFree(DWORD(PerHandleData));
GlobalFree(DWORD(PerIoData));
Continue;
end;

if PerIoData.BytesRECV = 0 then
begin
PerIoData.BytesRECV := BytesTransferred;
PerIoData.BytesSEND := 0;
end
else begin
PerIoData.BytesSEND := PerIoData.BytesSEND + BytesTransferred;
end;

if PerIoData.BytesRECV > PerIoData.BytesSEND then
begin
ZeroMemory(@(PerIoData.Overlapped), SizeOf(TOverlapped));
PerIoData.DataBuf.buf := PerIoData.Buffer + PerIoData.BytesSEND;
PerIoData.DataBuf.len := PerIoData.BytesRECV - PerIoData.BytesSEND;

if WSASend(PerHandleData.Socket, @(PerIoData^.DataBuf), 1, @SendBytes, 0,
@(PerIoData^.Overlapped), nil) = SOCKET_ERROR then
raise ESocketError.Create();
end
else begin
PerIoData.BytesRECV := 0;

Flags := 0;
ZeroMemory(@(PerIoData.Overlapped), SizeOf(TOverlapped));

PerIoData.DataBuf.len := DATA_BUFSIZE;
PerIoData.DataBuf.buf := @PerIoData.Buffer[0];

if WSARecv(PerHandleData.Socket, @(PerIoData^.DataBuf), 1, @RecvBytes, @Flags,
@(PerIoData^.Overlapped), nil) = SOCKET_ERROR then
raise ESocketError.Create();
end;

end;
end;

{ TSimpleICOP }

constructor TSimpleICOP.Create;
begin
FLocalSockHandle := -1;
FCompletionPort := 0;
FRemoteSockHandle := -1;
end;

procedure TSimpleICOP.Free;
begin
closesocket(FLocalSockHandle);
end;

procedure TSimpleICOP.InitSocket;
var
i: Integer;
Flags: DWORD;
RecvBytes: DWORD;
ThreadHandle: THandle;
ThreadID: DWORD;
begin
FCompletionPort := CreateIoCompletionPort(INVALID_HANDLE_VALUE,
0, 0, 0);
if FCompletionPort = 0 then raise ESocketError.Create();
//»ñµÃÍê³É¶Ë¿Ú¾ä±ú

GetSystemInfo(FSystemInfo);
//µÃµ½CPUÊýÁ¿

for i := 0 to FSystemInfo.dwNumberOfProcessors * 2 - 1 do
begin
ThreadHandle := CreateThread(nil, 0, @ServerWorkerThread,
Pointer(FCompletionPort), 0, ThreadID);
if ThreadHandle = 0 then raise ESocketError.Create();
CloseHandle(ThreadHandle);
end;
//´´½¨¹¤×÷Ị̈߳¬ÊýÁ¿ÎªCPUÊýÁ¿µÄ2±¶

FLocalSockHandle := WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);
if FLocalSockHandle = INVALID_SOCKET then raise ESocketError.Create();
//´´½¨Ò»¸öÌ×½Ó¿Ú

FLocalSockAddrIn.sin_family := AF_INET;
FLocalSockAddrIn.sin_port := htons(SERV_PORT);
FLocalSockAddrIn.sin_addr.S_addr := htonl(INADDR_ANY);

if bind(FLocalSockHandle, @FLocalSockAddrIn, SizeOf(FLocalSockAddrIn)) <> 0 then
raise ESocketError.Create();
//°ó¶¨Ì×½Ó¿Ú

if listen(FLocalSockHandle, SOCK_STREAM) <> 0 then raise ESocketError.Create();
//¿ªÊ¼¼àÌý

while True do
begin
FRemoteSockHandle := WSAAccept(FLocalSockHandle, nil, nil, nil, 0);
if FRemoteSockHandle = INVALID_SOCKET then
raise ESocketError.Create();

FPerHandleData := LPPER_HANDLE_DATA(GlobalAlloc(GPTR, SizeOf(PER_HANDLE_DATA)));
if FPerHandleData = nil then raise ESocketError.Create();
//´´½¨Ò»¸ö¹Ø¼üÏîÓÃÓÚ±£´æÕâ¸ö¿Í»§¶ËµÄÐÅÏ¢£¬Óû§½ÓÊÕ·¢Ë͵ÄÖصþ½á¹¹£¬
//»¹ÓÐʹÓõ½µÄ»º³åÇø

FPerHandleData.Socket := FRemoteSockHandle;

if CreateIoCompletionPort(FRemoteSockHandle,
FCompletionPort, DWORD(FPerHandleData), 0) = 0 then
raise ESocketError.Create();
//Íê³ÉÌ×½Ó¿ÚºÍÍê³É¶Ë¿ÚÖ®¼äµÄ¹ØÁª

FPerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, SizeOf(PER_IO_OPERATION_DATA)));
if FPerIoData = nil then raise ESocketError.Create();
//ͶµÝÒ»´Î½ÓÊÕ£¬ÓÉÓÚ½ÓÊÕ¶¼ÐèҪʹÓÃÕâ¸öº¯ÊýÀ´Í¶µÝÒ»¸ö½ÓÊÕµÄ×¼±¸

ZeroMemory(@(FPerIoData^.Overlapped), SizeOf(TOverlapped));
FPerIoData^.BytesSEND := 0;
FPerIoData^.BytesRECV := 0;
FPerIoData^.DataBuf.len := DATA_BUFSIZE;
FPerIoData^.DataBuf.buf := @(FPerIoData^.Buffer[0]);
Flags := 0;

//就是这里,出现977的错误!
if WSARecv(FRemoteSockHandle, @(FPerIoData^.DataBuf), 1, @RecvBytes, @Flags,
@(FPerIoData^.Overlapped), nil) = SOCKET_ERROR then
raise ESocketError.Create();

end;
//¿ªÊ¼½ÓÊÕ´Ó¿Í»§¶ËÀ´µÄÁ¬½Ó

end;

class procedure TSimpleICOP.StartSocket;
var
WsData: TWSAData;
begin
if WSAStartup(MAKEWORD(2, 2), WsData) <> 0 then raise ESocketError.Create();
end;

class procedure TSimpleICOP.StopSocket;
begin
WSACleanup;
end;

{ ESocketError }

constructor ESocketError.Create();
var
iErr: Integer;
i: Integer;
ErrorMessage: Pointer;
ErrorCode: DWORD;
begin
iErr := WSAGetLastError();
for i := Low(ScoketExceptionLists) to High(ScoketExceptionLists) do
if iErr = ScoketExceptionLists.ErrCode then
CreateFmt('ErrCode: %d, ErrText: %s', [ScoketExceptionLists.ErrCode,
ScoketExceptionLists.ErrText]);

ErrorCode := GetLastError;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
nil, ErrorCode, 0, @ErrorMessage, 0, nil);
CreateFmt('ErrCode: %d, ErrText: %s', [ErrorCode, string(PChar(ErrorMessage))]);
LocalFree(hlocal(ErrorMessage));

{$IFDEF CONSOLE}

{$ENDIF}
end;

initialization
TSimpleICOP.StartSocket;
finalization
TSimpleICOP.StopSocket;

end.
 
IOCP的操作,在WSARecv的时候就出现这个错误,郁闷:
unit IOCP;

interface
uses SysUtils, Classes, Windows, WinSock2, SocketExceptionCounts;

const
SERV_PORT = 9877;
DATA_BUFSIZE = 8192;
type
{
TCPOverlapped = record
Overlapped: _OVERLAPPED;
OVKey: Integer;
IsRead: Boolean;
Buffer: WSABUF;
SendingData: string;
end;
PCPOverlapped = ^TCPOverlapped;

//¹Ø¼üÏî
PER_IO_OPERATION_DATA = packed record
Overlapped: TOverlapped;
DataBuf: TWSABUF;
Buffer: array [0..DATA_BUFSIZE - 1] of Char;
BytesSEND: DWORD;
BytesRECV: DWORD;
end;
}
//¹Ø¼üÏî
PER_IO_OPERATION_DATA = packed record
Overlapped: TOverlapped;
DataBuf: TWSABUF;
Buffer: array [0..DATA_BUFSIZE - 1] of Char;
BytesSEND: DWORD;
BytesRECV: DWORD;
end;


LPPER_IO_OPERATION_DATA = ^PER_IO_OPERATION_DATA;

PER_HANDLE_DATA = packed record
Socket: TSocket;
end;

LPPER_HANDLE_DATA = ^PER_HANDLE_DATA;


ESocketError = class(Exception)
public
constructor Create(); overload;
public
property HelpContext;
property Message;
end;

TSimpleICOP = class(TObject)
private
FLocalSockHandle: TSocket;
FLocalSockAddrIn: TSockAddrIn;
FCompletionPort: THandle;
FSystemInfo: TSystemInfo;
FRemoteSockHandle: TSocket;

FPerHandleData: LPPER_HANDLE_DATA;
FPerIoData: LPPER_IO_OPERATION_DATA;
private
class procedure StartSocket();
class procedure StopSocket();
public
constructor Create;
procedure Free;
public
procedure InitSocket();
end;

function ServerWorkerThread(CompletionPortID: THandle): DWORD; stdcall;


implementation

function ServerWorkerThread(CompletionPortID: THandle): DWORD; stdcall;
var
CompletionPort: THandle;
BytesTransferred: DWORD;
PerHandleData: LPPER_HANDLE_DATA;
PerIoData: LPPER_IO_OPERATION_DATA;
SendBytes, RecvBytes, Flags: DWORD;
begin
CompletionPort := THandle(CompletionPortID);

while True do
begin
if GetQueuedCompletionStatus(CompletionPort, BytesTransferred,
DWORD(PerHandleData), POverlapped(PerIoData), INFINITE) = LongBool(0) then
raise ESocketError.Create();

if BytesTransferred = 0 then
begin
if closesocket(PerHandleData.Socket) = SOCKET_ERROR then raise ESocketError.Create();

GlobalFree(DWORD(PerHandleData));
GlobalFree(DWORD(PerIoData));
Continue;
end;

if PerIoData.BytesRECV = 0 then
begin
PerIoData.BytesRECV := BytesTransferred;
PerIoData.BytesSEND := 0;
end
else begin
PerIoData.BytesSEND := PerIoData.BytesSEND + BytesTransferred;
end;

if PerIoData.BytesRECV > PerIoData.BytesSEND then
begin
ZeroMemory(@(PerIoData.Overlapped), SizeOf(TOverlapped));
PerIoData.DataBuf.buf := PerIoData.Buffer + PerIoData.BytesSEND;
PerIoData.DataBuf.len := PerIoData.BytesRECV - PerIoData.BytesSEND;

if WSASend(PerHandleData.Socket, @(PerIoData^.DataBuf), 1, @SendBytes, 0,
@(PerIoData^.Overlapped), nil) = SOCKET_ERROR then
raise ESocketError.Create();
end
else begin
PerIoData.BytesRECV := 0;

Flags := 0;
ZeroMemory(@(PerIoData.Overlapped), SizeOf(TOverlapped));

PerIoData.DataBuf.len := DATA_BUFSIZE;
PerIoData.DataBuf.buf := @PerIoData.Buffer[0];

if WSARecv(PerHandleData.Socket, @(PerIoData^.DataBuf), 1, @RecvBytes, @Flags,
@(PerIoData^.Overlapped), nil) = SOCKET_ERROR then
raise ESocketError.Create();
end;

end;
end;

{ TSimpleICOP }

constructor TSimpleICOP.Create;
begin
FLocalSockHandle := -1;
FCompletionPort := 0;
FRemoteSockHandle := -1;
end;

procedure TSimpleICOP.Free;
begin
closesocket(FLocalSockHandle);
end;

procedure TSimpleICOP.InitSocket;
var
i: Integer;
Flags: DWORD;
RecvBytes: DWORD;
ThreadHandle: THandle;
ThreadID: DWORD;
begin
FCompletionPort := CreateIoCompletionPort(INVALID_HANDLE_VALUE,
0, 0, 0);
if FCompletionPort = 0 then raise ESocketError.Create();
//»ñµÃÍê³É¶Ë¿Ú¾ä±ú

GetSystemInfo(FSystemInfo);
//µÃµ½CPUÊýÁ¿

for i := 0 to FSystemInfo.dwNumberOfProcessors * 2 - 1 do
begin
ThreadHandle := CreateThread(nil, 0, @ServerWorkerThread,
Pointer(FCompletionPort), 0, ThreadID);
if ThreadHandle = 0 then raise ESocketError.Create();
CloseHandle(ThreadHandle);
end;
//´´½¨¹¤×÷Ị̈߳¬ÊýÁ¿ÎªCPUÊýÁ¿µÄ2±¶

FLocalSockHandle := WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);
if FLocalSockHandle = INVALID_SOCKET then raise ESocketError.Create();
//´´½¨Ò»¸öÌ×½Ó¿Ú

FLocalSockAddrIn.sin_family := AF_INET;
FLocalSockAddrIn.sin_port := htons(SERV_PORT);
FLocalSockAddrIn.sin_addr.S_addr := htonl(INADDR_ANY);

if bind(FLocalSockHandle, @FLocalSockAddrIn, SizeOf(FLocalSockAddrIn)) <> 0 then
raise ESocketError.Create();
//°ó¶¨Ì×½Ó¿Ú

if listen(FLocalSockHandle, SOCK_STREAM) <> 0 then raise ESocketError.Create();
//¿ªÊ¼¼àÌý

while True do
begin
FRemoteSockHandle := WSAAccept(FLocalSockHandle, nil, nil, nil, 0);
if FRemoteSockHandle = INVALID_SOCKET then
raise ESocketError.Create();

FPerHandleData := LPPER_HANDLE_DATA(GlobalAlloc(GPTR, SizeOf(PER_HANDLE_DATA)));
if FPerHandleData = nil then raise ESocketError.Create();
//´´½¨Ò»¸ö¹Ø¼üÏîÓÃÓÚ±£´æÕâ¸ö¿Í»§¶ËµÄÐÅÏ¢£¬Óû§½ÓÊÕ·¢Ë͵ÄÖصþ½á¹¹£¬
//»¹ÓÐʹÓõ½µÄ»º³åÇø

FPerHandleData.Socket := FRemoteSockHandle;

if CreateIoCompletionPort(FRemoteSockHandle,
FCompletionPort, DWORD(FPerHandleData), 0) = 0 then
raise ESocketError.Create();
//Íê³ÉÌ×½Ó¿ÚºÍÍê³É¶Ë¿ÚÖ®¼äµÄ¹ØÁª

FPerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, SizeOf(PER_IO_OPERATION_DATA)));
if FPerIoData = nil then raise ESocketError.Create();
//ͶµÝÒ»´Î½ÓÊÕ£¬ÓÉÓÚ½ÓÊÕ¶¼ÐèҪʹÓÃÕâ¸öº¯ÊýÀ´Í¶µÝÒ»¸ö½ÓÊÕµÄ×¼±¸

ZeroMemory(@(FPerIoData^.Overlapped), SizeOf(TOverlapped));
FPerIoData^.BytesSEND := 0;
FPerIoData^.BytesRECV := 0;
FPerIoData^.DataBuf.len := DATA_BUFSIZE;
FPerIoData^.DataBuf.buf := @(FPerIoData^.Buffer[0]);
Flags := 0;

//就是这里,出现977的错误!
if WSARecv(FRemoteSockHandle, @(FPerIoData^.DataBuf), 1, @RecvBytes, @Flags,
@(FPerIoData^.Overlapped), nil) = SOCKET_ERROR then
raise ESocketError.Create();

end;
//¿ªÊ¼½ÓÊÕ´Ó¿Í»§¶ËÀ´µÄÁ¬½Ó

end;

class procedure TSimpleICOP.StartSocket;
var
WsData: TWSAData;
begin
if WSAStartup(MAKEWORD(2, 2), WsData) <> 0 then raise ESocketError.Create();
end;

class procedure TSimpleICOP.StopSocket;
begin
WSACleanup;
end;

{ ESocketError }

constructor ESocketError.Create();
var
iErr: Integer;
i: Integer;
ErrorMessage: Pointer;
ErrorCode: DWORD;
begin
iErr := WSAGetLastError();
for i := Low(ScoketExceptionLists) to High(ScoketExceptionLists) do
if iErr = ScoketExceptionLists.ErrCode then
CreateFmt('ErrCode: %d, ErrText: %s', [ScoketExceptionLists.ErrCode,
ScoketExceptionLists.ErrText]);

ErrorCode := GetLastError;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
nil, ErrorCode, 0, @ErrorMessage, 0, nil);
CreateFmt('ErrCode: %d, ErrText: %s', [ErrorCode, string(PChar(ErrorMessage))]);
LocalFree(hlocal(ErrorMessage));

{$IFDEF CONSOLE}

{$ENDIF}
end;

initialization
TSimpleICOP.StartSocket;
finalization
TSimpleICOP.StopSocket;

end.
 
我不明白你的WinSock在干什么,但是IO错误我知道,肯定是你对一个已经打开的流再一次打开,或者没有完全释放引起怕,
如用流的话,不进行freeandnil(流),是不行的,只FREE,有时会也出错
 
异步IO时,你要进一步判断
WSAGetLastError() <> WSA_IO_PENDING
如果是WSA_IO_PENDING不算错误, 因为操作的确没完成
 
tseug:
原来是WSA_IO_PENDING错误,真是糊涂,谢谢你了,忽略这个错误之后程序运行得很好!
 
后退
顶部