简单的TClientSocket、TServerSocket发送接收消息程序ServerSocket1的OnClientDisconnect问题

ooolinux 2018-01-01 03:01:14
简单的TClientSocket、TServerSocket发送接收消息程序ServerSocket1的OnClientDisconnect问题:
客户端进程断开连接后,服务器端程序的代码
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
TCustomWinSocket *Socket)
{
if(ServerSocket1->Active)//&&ServerSocket1->Socket->SocketHandle!=INVALID_SOCKET)
ServerSocket1->Close();
}
//---------------------------------------------------------------------------

必定会产生异常,提示消息有以下几种:
(1)Privileged instruction
(2)Access violation at address xxxx. Read of address yyyy
(3)Access violation at address xxxx. Write of address yyyy
多数情况是出现第2、3种,这是什么原因呢?
...全文
2068 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
我测试了一下TServerSocket的功能,实际上不需要ServerSocket1->Close();或者ServerSocket1->Socket->Close();或者ServerSocket1->Socket->Connections[x]->Close(); 因为ClientDisconnect事件处理被调用的时候,对应的那个Socket已经被关闭了,你可以检查一下ServerSocket1->Socket->ActiveConnections,这个值随着传入的连接增加在增加,ClientDisconnect的时候减少,但是减到1为止,也就是TServerSocket在有客户连接进来之后至少保留一个Socket用于重用,直到TServerSocket->Active=false;才关闭。
ooolinux 2018-02-09
  • 打赏
  • 举报
回复
@早打大打打核战争 如果一个局域网打牌,只有一个程序够吗,一台电脑上程序作为服务器,另几台电脑上同一个程序作为客户端?感觉需要一个中转,或者把服务器角色作为中转?
  • 打赏
  • 举报
回复
你说的这种情况是因为原先TServerSocket监听了某端口,另一个程序再监听同一端口(估计你是在同一机器上测试的)肯定不行,测试的时候副本监听另一端口就可以了。这种应用应该放一个TServerSocket接受别人进来的连接,然后动态创建若干TClientSocket去主动连接别人,否则把TServerSocket切换为client去连接别人的时候,其他人要主动连接你j就不行了。
ooolinux 2018-02-09
  • 打赏
  • 举报
回复
@早打大打打核战争 我有一个demo程序,是集客户端与服务器端于一体的,其中一个作为server,另一个作为client连接,断开连接后,如果ServerSocket1->Close();以后,原来作为client的现在可以作为server,另一个反过来作为client连接,如果不Close(),原来作为client的现在想做server监听时,会提示错误,因为端口没有被释放。
abc_ustone 2018-02-08
  • 打赏
  • 举报
回复
看看
ooolinux 2018-02-08
  • 打赏
  • 举报
回复
我貌似发现了,ServerSocket1->Close()会导致 while FConnections.Count > 0 do TCustomWinSocket(FConnections.Last).Free; 然后 procedure TCustomWinSocket.DeferFree; begin if FHandle <> 0 then PostMessage(FHandle, CM_DEFERFREE, 0, 0); end; procedure TCustomWinSocket.CMDeferFree(var Message); begin Free; end; 会导致连接被重复Free出问题,但是不知道代码该怎么改?
ooolinux 2018-02-08
  • 打赏
  • 举报
回复
ServerSocket1->Close()的VCL源代码如下,不是很懂:
procedure TAbstractSocket.Close;
begin
  Active := False;
end;


procedure TAbstractSocket.SetActive(Value: Boolean);
begin
  if Value <> FActive then
  begin
    if (csDesigning in ComponentState) or (csLoading in ComponentState) then
      FActive := Value;
    if not (csLoading in ComponentState) then
      DoActivate(Value);
  end;
end;


procedure TCustomServerSocket.DoActivate(Value: Boolean);
begin
  if (Value <> FServerSocket.Connected) and not (csDesigning in ComponentState) then
  begin
    if FServerSocket.Connected then
      FServerSocket.Disconnect(FServerSocket.SocketHandle)
    else FServerSocket.Listen(FHost, FAddress, FService, FPort, SOMAXCONN);
  end;
end;


procedure TServerWinSocket.Disconnect(Socket: TSocket);
var
  SaveCacheSize: Integer;
begin
  Lock;
  try
    SaveCacheSize := ThreadCacheSize;
    try
      ThreadCacheSize := 0;
      while FActiveThreads.Count > 0 do
        with TServerClientThread(FActiveThreads.Last) do
        begin
          FreeOnTerminate := False;
          Terminate;
          FEvent.SetEvent;
          if (ClientSocket <> nil) and ClientSocket.Connected then
            ClientSocket.Close;
          WaitFor;  
          Free;
        end;
      while FConnections.Count > 0 do
        TCustomWinSocket(FConnections.Last).Free;
      if FServerAcceptThread <> nil then
        FServerAcceptThread.Terminate;
      inherited Disconnect(Socket);
      FServerAcceptThread.Free;
      FServerAcceptThread := nil;
    finally
      ThreadCacheSize := SaveCacheSize;
    end;
  finally
    Unlock;
  end;
end;

ooolinux 2018-02-08
  • 打赏
  • 举报
回复
我看了下VCL源代码:
procedure TServerWinSocket.ClientDisconnect(Socket: TCustomWinSocket);
begin
  if Assigned(FOnClientDisconnect) then FOnClientDisconnect(Self, Socket);
  if ServerType = stNonBlocking then Socket.DeferFree;
end;

procedure TCustomWinSocket.DeferFree;
begin
  if FHandle <> 0 then PostMessage(FHandle, CM_DEFERFREE, 0, 0);
end;

procedure TCustomWinSocket.CMDeferFree(var Message);
begin
  Free;
end;
那这个代码:
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
    if(ServerSocket1->Active)//&&ServerSocket1->Socket->SocketHandle!=INVALID_SOCKET)
        ServerSocket1->Close();
}
//---------------------------------------------------------------------------
为什么会出问题呢?在ButtonClick里 if(ServerSocket1->Active) ServerSocket1->Close(); 是没问题的。
ooolinux 2018-02-08
  • 打赏
  • 举报
回复
用消息映射+发送自定义消息,或者给一个按钮PostMessage(btnDisconnect->Handle,BM_CLICK,0,0); 在btnDisconnectClick里 if(ServerSocket1->Active) ServerSocket1->Close(); 解决了。 不知道有没有更好的方法,有没有类似TThread::Synchronize那样的方法?
ooolinux 2018-01-08
  • 打赏
  • 举报
回复
@chenlei 明白了~
chenlei 2018-01-08
  • 打赏
  • 举报
回复
indy是阻塞模式,winsocket工作在事件驱动模式。
Mr Dang 2018-01-02
  • 打赏
  • 举报
回复
客户端已经要断开了触发的断开事件,你还手动Socket->Close干嘛 ?
ooolinux 2018-01-02
  • 打赏
  • 举报
回复
@DelphiGuy 看了几个例子,感觉Indy还是蛮方便的,发送字符串、发送文件、发送流都只要一句调用函数的代码。 不知道Indy是什么机制,感觉只管发,只管收,没有什么OnRead、OnWrite、OnClientRead、OnClientWrite? sourceforge 通过网页怎么打包下载最新版的?我下的是108, Commit [r108] Authored by: bdlm 2013-03-17 而首页是: Summary Last Update: 2016-07-16
ooolinux 2018-01-02
  • 打赏
  • 举报
回复
@DelphiGuy 如果有CB的例子就好了~
ooolinux 2018-01-02
  • 打赏
  • 举报
回复
@a295281315 它依然是Active的,这个程序是为了说明,我另一个完整一点的程序需要这么用的,可以反复地连接、断开。
ooolinux 2018-01-01
  • 打赏
  • 举报
回复
C++ Builder源代码在此贴: http://bbs.csdn.net/topics/392303481

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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