作过完成端口的朋友请进,帮一下忙,谢谢

sodme 2004-09-15 07:00:21
我的完成端口服务器模型最近遇到一个很头大的问题,在执行GetQueuedCompletionStatus时会报错,错误代码用GetLastError通常取到的是:64,有的时候也会取到:995,GetQueuedCompletionStatus函数出错后,完成端口模型就会停止响应任何的网络IO操作,造成服务器当机,不知道这里有没有用DELPHI作过完成端口的朋友,如果有的话,还望一定帮忙,给个解决思路。顺便说一下,我作的是游戏服务器。分不够可以再加,完成端口的问题已经困扰我一个多星期了,已经严重影响了项目进度,请大家一定帮忙。谢谢了。
...全文
445 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2005-04-14
  • 打赏
  • 举报
回复
这个问题,我已经解决。当初遇到的问题是,大厅服务器和房间服务器死锁,即服务器已经没有任何响应,这是因为线程同步异常导致的死锁。64错误,可以忽略不计,也可以进行一定的异常处理,但它不是造成服务器死锁的原因,造成服务器死锁的原因是我在服务器中使用的几个同步变量的同步异常。

再次感谢大家。
skykeen 2005-02-12
  • 打赏
  • 举报
回复
沙发
lamputa_lito 2005-02-06
  • 打赏
  • 举报
回复
我的完成端口服务器模型最近遇到一个很头大的问题,在执行GetQueuedCompletionStatus时会报错,错误代码用GetLastError通常取到的是:64,有的时候也会取到:995

错误64一般是因为由于SOCKET连接已经关闭,所以遇到这个错误的时候,你可以不理会,继续GetQueuedCompletionStatus,对于已关闭的SOCKET,下一次GetQueuedCompletionStatus就不会再有错误,至于995,使完成端口已经被关闭,说明该完成端口已不可用,只能退出。
「已注销」 2004-09-20
  • 打赏
  • 举报
回复
嗯,谢谢三哥了。呵呵。
copy_paste 2004-09-18
  • 打赏
  • 举报
回复
一般写服务的操作,一般都是操作频繁,你这加锁,那多个工作线程相互影响.不好
而且,我试过使用CS很容易造成死锁,很难找出原因,后来不使用CS后就没事了,所以,我尽量在这种操作中避免使用它.
Synchronize亦是如此.

减少全局变量的使用,也就是减少工作线程之间的互锁

消息很简单吧,就是PostMessage过去,通知主线程,再相应操作.
「已注销」 2004-09-17
  • 打赏
  • 举报
回复
谢谢木石三,我想请问一下,为什么要把globallock去掉,而且,为什么不能用它来频繁加锁?这里面当端口关闭时,是要从clientlist中删除元素的,不会与其它产生线程产生冲突吗?

如果用消息,能提示一下如何作吗?非常感谢。
copy_paste 2004-09-17
  • 打赏
  • 举报
回复
这个好理解,指针的好处就是可以乱来,不过不小心也会中招.不然MS也不用来定义那么多的.H文件来存放那些乱七八糟的struct格式

还有你将GlobalLock加锁功能先去掉,D里面,最好不要用它来在频繁加锁,Synchronize方法也不要用,用消息.
全局变量能少用的就少用
「已注销」 2004-09-17
  • 打赏
  • 举报
回复
谢谢以上的各位,有一点我始终不明白,在GetQueuedCompletionStatus的原型中,LPOVERPAPPED类型是一个overlapped的指针,而handledata是用户自定义的一个数据,这个HANDLEDATA结构体的第一个元素是OVERLAPPED,这里直接用POVERLAPPED(HANDLEDATA)有没有问题?从返回结果和执行的情况看,似乎又是可行的。
rwdx 2004-09-16
  • 打赏
  • 举报
回复
BOOL GetQueuedCompletionStatus(

HANDLE CompletionPort, // the I/O completion port of interest
LPDWORD lpNumberOfBytesTransferred, // to receive number of bytes transferred during I/O
LPDWORD lpCompletionKey, // to receive file's completion key
LPOVERLAPPED *lpOverlapped, // to receive pointer to OVERLAPPED structure
DWORD dwMilliseconds // optional timeout value
);


GetQueuedCompletionStatus(FServerComm.FListenPort, byteRece, @<这个地方应该是完成键结构指针>, @LTempHandleData<此处应该是接收重叠IO的指针>, INFINITE)
rwdx 2004-09-16
  • 打赏
  • 举报
回复
if not GetQueuedCompletionStatus(FServerComm.FListenPort, byteRece, Key, POverlapped(HandleData), INFINITE) then

byteRece
Key

这两个参数好像应该是传地址吧,HandleData参数应该是双指针
Kendiv 2004-09-16
  • 打赏
  • 举报
回复
64 可以认为是用户断线了,正常或非正常
995 表示完成端口已关闭
「已注销」 2004-09-16
  • 打赏
  • 举报
回复
to 牙科医生:
造成64错误的原因是什么?网络名不可用是指的哪个不可用?socket不可用吗?这个错误是我在调用GetQueuedCompletionStatus时出现的,还望能更详细的解释一下。另外,socket=>SOCKET表示的是什么含义?对不起,麻烦你了。

还请大家继续帮着看看,昨晚又追踪了一个晚上,睡觉前(3点左右)游戏还是可以继续进行的,但今天早晨醒来时,房间服务器和大厅服务器已经无法通信了。

以下是我的工作者线程代码:




procedure TIOCPProcThread.Execute;
var
HandleData: PPerHandleData;
LTempHandleData: POverlapped;
byteRece, Key: DWORD;
OperPosted: boolean;
errCode: integer;
IOCPClientIndex : integer;
Socket_Str: string;
LIOCPClient: TIOCPClient;
begin
Key := 0;
while not Terminated do
begin
if not GetQueuedCompletionStatus(FServerComm.FListenPort, byteRece, Key, POverlapped(HandleData), INFINITE) then
begin
errCode := GetLastError;

if IOCP_DEBUGED then
begin
DebugOut('工作者线程执行Get函数时出错,当前处理将被舍弃,错误编码(win):'+ inttostr(GetLastError));
DebugOut('工作者线程执行Get函数时出错,当前处理将被舍弃,错误编码(WSA):'+ inttostr(WSAGetLastError));
end;

if errcode = 6 then
begin
if IOCP_DEBUGED then
DebugOut('工作者线程执行Get函数时出现严重错误,线程将被终止');
Terminate;
end;
Continue;
end;

if Finished then
begin
if IOCP_DEBUGED then
DebugOut('工作者线程因完成而被终止');
Terminate;
end;

GlobalLock.Enter;

//客户端断开连接
if (byteRece = 0) and (HandleData.Statu=ssRecv) then
begin
FLogMsg := Format('客户端断开连接:%d', [HandleData.Socket]);
Synchronize(Log);
FServerComm.DoClientClose(HandleData.Socket);
//DebugOut('释放地址:' + inttostr(HandleData.Socket));
//Dispose(HandleData);
GlobalLock.Leave;
Continue;
end;

case HandleData.Statu of
ssRecv:
begin
OperPosted := false;
if Assigned(FServerComm.FOnDataRecive) then
FServerComm.FOnDataRecive(HandleData, OperPosted, byteRece);
Socket_Str := inttostr(HandleData.Socket);
IOCPClientIndex := FServerComm.FIOCPClientList.IndexOf(Socket_Str);
if IOCPClientIndex<>-1 then
begin
LIOCPClient := TIOCPClient(FServerComm.FIOCPClientList.Objects[IOCPClientIndex]);
LIOCPClient.RecvCount := LIOCPClient.RecvCount-1;
if LIOCPClient.RecvCount<=0 then
begin
if IOCP_DEBUGED then
DebugOut('工作者线程在Recv后执行PostRead');
LIOCPClient.RecvCount := LIOCPClient.RecvCount + 1;
PostRead(HandleData.Socket, IOCPClientIndex);
end;
end;
end;
ssSend:
begin
OperPosted := false;
if Assigned(FServerComm.FOnDataSend) then
FServerComm.FOnDataSend(HandleData, OperPosted);
Socket_Str := inttostr(HandleData.Socket);
IOCPClientIndex := FServerComm.FIOCPClientList.IndexOf(Socket_Str);
if IOCPClientIndex<>-1 then
begin
LIOCPClient := TIOCPClient(FServerComm.FIOCPClientList.Objects[IOCPClientIndex]);
if LIOCPClient.RecvCount<=0 then
begin
if IOCP_DEBUGED then
DebugOut('工作者线程在Send后执行PostRead');
LIOCPClient.RecvCount := LIOCPClient.RecvCount + 1;
PostRead(HandleData.Socket, IOCPClientIndex);
end;
end;
if HandleData<>nil then
begin
FreeMem(HandleData.WSABuffer.buf);
end;
end;
ssClose:
begin
if IOCP_DEBUGED then
DebugOut('工作者线程在因ssClose标记而执行DOClientClose');
FServerComm.DoClientClose(HandleData.Socket);
end;
ssStop:
begin
if IOCP_DEBUGED then
DebugOut('工作者线程在因ssStop标记将被终止');
Dec(FServerComm.FCount);
Terminate;
end;
end; // Case

//DebugOut('释放地址:' + inttostr(HandleData.Socket));
//Dispose(HandleData);
GlobalLock.Leave;
end;
end;



DentistryDoctor 2004-09-16
  • 打赏
  • 举报
回复
Socket=>SOCKET
DentistryDoctor 2004-09-16
  • 打赏
  • 举报
回复
64,指定的网络名不可用。
995由于线程退出或应用程序请求,已放弃 I/O 操作。
证明你线程退出时没有关闭某些句柄造成的。<可能主要是Socket>
tianxiangyuan 2004-09-16
  • 打赏
  • 举报
回复
先搜索一下以前的帖子。
rwdx 2004-09-15
  • 打赏
  • 举报
回复
最好贴出你的代码看看,

4,387

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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