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

ooolinux 2018-01-01 03:01:06
简单的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种,这是什么原因呢?
...全文
1513 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
见另一贴...
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;

abc_ustone 2018-02-08
  • 打赏
  • 举报
回复
看看
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-02
  • 打赏
  • 举报
回复
这个程序是为了说明,我另一个完整一点的程序需要这么用的,可以反复地连接、断开。
ooolinux 2018-01-01
  • 打赏
  • 举报
回复
主要源代码如下,分为Client和Server两个项目: ClientUnit1.h
//---------------------------------------------------------------------------

#ifndef ClientUnit1H
#define ClientUnit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <ScktComp.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
    TEdit *edtAddress;
    TEdit *edtPort;
    TButton *btnConnect;
    TEdit *Edit1;
    TLabel *Label1;
    TButton *btnSend;
    TStatusBar *StatusBar1;
    TClientSocket *ClientSocket1;
    void __fastcall btnConnectClick(TObject *Sender);
    void __fastcall ClientSocket1Connect(TObject *Sender,
          TCustomWinSocket *Socket);
    void __fastcall FormDestroy(TObject *Sender);
    void __fastcall btnSendClick(TObject *Sender);
    void __fastcall FormCreate(TObject *Sender);
private:	// User declarations
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
ClientUnit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "ClientUnit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    StatusBar1->SimpleText="未连接";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConnectClick(TObject *Sender)
{
    if(edtAddress->Text==""||edtPort->Text=="")
    {
        ShowMessage("请输入服务端地址和端口");
        return;
    }
    ClientSocket1->Address=edtAddress->Text;//127.0.0.1
    ClientSocket1->Port=edtPort->Text.ToInt();//9999
    ClientSocket1->Open();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,
      TCustomWinSocket *Socket)
{
    StatusBar1->SimpleText="已连接";    
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
    if(ClientSocket1->Active)
        ClientSocket1->Close();    
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSendClick(TObject *Sender)
{
    if(Edit1->Text=="")
    {
        ShowMessage("请输入要发送的文本");
        return;
    }
    if(ClientSocket1->Active)
    {
        ClientSocket1->Socket->SendText(Edit1->Text);
        Edit1->Clear();
    }
    else
    {
        ShowMessage("请先连接");
    }
}
//---------------------------------------------------------------------------

ServerUnit1.h
//---------------------------------------------------------------------------

#ifndef ServerUnit1H
#define ServerUnit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ScktComp.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
    TMemo *Memo1;
    TLabel *Label1;
    TServerSocket *ServerSocket1;
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall FormDestroy(TObject *Sender);
    void __fastcall ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket);
    void __fastcall ServerSocket1ClientDisconnect(TObject *Sender,
          TCustomWinSocket *Socket);
private:	// User declarations
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
ServerUnit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "ServerUnit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    ServerSocket1->Port=9999;
    ServerSocket1->Open();    
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
    if(ServerSocket1->Active)
        ServerSocket1->Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
    Memo1->Lines->Add(Socket->ReceiveText());    
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
    if(ServerSocket1->Active)//&&ServerSocket1->Socket->SocketHandle!=INVALID_SOCKET)
        ServerSocket1->Close();
}
//---------------------------------------------------------------------------

1,316

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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