使用ServerSocket和ClientSocket的问题???高手来看看 ( 积分: 100 )

  • 主题发起人 主题发起人 zepplin79
  • 开始时间 开始时间
Z

zepplin79

Unregistered / Unconfirmed
GUEST, unregistred user!
这个程序主要是想让Server(非阻塞)和Client(阻塞)运行一个协议:大致的格式如下:
hello word100
我的问题主要有3个:
1、ClientSokcet给ServerSocket发信息,如果只是发送hello word,则程序可以很好的工作。但是如果后面再加上别的控制字,如一个byte类型的整数,则程序在跳出
ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket);这个过程的时候,会出现一个异常 Access Viloation at address。。。
2、如果我的协议头比较长,30到40个字节,是不是不能保证ServerSocket1ClientRead过程一次能接收完毕,我该怎么做?》
3、如果服务器端没有起来,直接ClientSocket.active:=true;时发出现一个异常,我在ClientonError中写了捕捉代码还是不行,后在加入了try excetp还是不行.
程序代码如下
代码:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdAntiFreezeBase, IdAntiFreeze, IdTCPServer,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,strutils,
  ScktComp;

type
  TFormMain = class(TForm)
    GroupBox1: TGroupBox;
    BtnConnect: TButton;
    BtnSend: TButton;
    BtnDisconnect: TButton;
    GroupBox2: TGroupBox;
    BtnStop: TButton;
    BtnStart: TButton;
    Lblog: TListBox;
    EdtHost: TEdit;
    EdtPort: TEdit;
    EdtData: TEdit;
    Button4: TButton;
    ServerSocket1: TServerSocket;
    ClientSocket1: TClientSocket;
   
    procedure BtnConnectClick(Sender: TObject);
    procedure BtnStartClick(Sender: TObject);
    procedure BtnStopClick(Sender: TObject);
    
    procedure AddLogEntry();
    procedure BtnDisconnectClick(Sender: TObject);
    procedure BtnSendClick(Sender: TObject);
    procedure ServerSocket1Accept(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Connecting(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
   
    
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormMain: TFormMain;
  FLogEntry,FReceived:string;

implementation

{$R *.dfm}


procedure TFormMain.BtnConnectClick(Sender: TObject);
begin
Clientsocket1.Address := EdtHost.Text;
ClientSocket1.Port := StrToInt(EdtPort.Text);
try
  ClientSocket1.Active := true;
except
  on E:exception  do
  showmessage('服务端没有监听');//这里的异常也不能被捕捉???
 end;
end;


procedure TFormMain.BtnStartClick(Sender: TObject);
begin
ServerSocket1.Port := StrToInt(EdtPort.Text);
Serversocket1.Active := True;
if serversocket1.Active=true then
begin
BtnStart.Enabled := False;
BtnStop.Enabled := True;
LbLog.Items.Add('服务器已成功启动!');
end
else
begin
BtnStart.Enabled :=true;
BtnStop.Enabled := false;
LbLog.Items.Add('服务器不能正常启动!');
end;
end;

procedure TFormMain.BtnStopClick(Sender: TObject);
begin
try
  Serversocket1.Active := False;
  BtnStart.Enabled := True;
  BtnStop.Enabled := False;
  LbLog.Items.Add('服务器已成功停止!');
except
  showmessage('服务器不能正常停止');
end;
end;

procedure TFormMain.AddLogEntry();
begin
  LbLog.Items.Add(FLogEntry);
end;

procedure TFormMain.BtnDisconnectClick(Sender: TObject);
begin
  ClientSocket1.Active:=false;
  LbLog.Items.Add('同主机 ' + EdtHost.Text + ' 的连接已断开!');
  BtnConnect.Enabled := True;
  BtnSend.Enabled := False;
  BtnDisconnect.Enabled := False;
end; 


procedure TFormMain.BtnSendClick(Sender: TObject);
  var Ptr:pointer;
      sendstr:string;
      SendStrLen:integer;
begin
  SendStr := 'hello word';
  SendStrLen:=length(SendStr);
try
  GetMem(ptr,11);//申请11个Byte
  CopyMemory(Ptr,pchar(sendstr),SendStrLen);//把‘hello word’拷贝到ptr指向的地址,占用10个字节
  pbyte(pchar(ptr)+10)^ :=100;//将指针偏移10个字节,指向第11个字节位置,写入byte类型值100
  LbLog.Items.Add('客户端发送:' + Sendstr);
  ClientSocket1.Socket.SendBuf(ptr,11);//组成一个协议头,发往ServerSocket
  FreeMem(ptr);
except
  LbLog.Items.Add('发送数据失败!');
  ClientSocket1.Active:=false;
  LbLog.Items.Add('同主机 ' + EdtHost.Text + ' 的连接已断开!');
  BtnConnect.Enabled := True;
  BtnSend.Enabled := False;
  BtnDisconnect.Enabled := False;
end;//end try
end;//

procedure TFormMain.ServerSocket1Accept(Sender: TObject;
  Socket: TCustomWinSocket);
  begin
    LbLog.Items.Add('From IP: '+socket.RemoteAddress+' 被接纳');
  end;

procedure TFormMain.ClientSocket1Connecting(Sender: TObject;
  Socket: TCustomWinSocket);
  begin
    Lblog.Items.Add('正在连接'+Edthost.Text+'....');
  end;

procedure TFormMain.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
  begin
    BtnConnect.Enabled := False;
    BtnSend.Enabled := True;
    BtnDisconnect.Enabled := True;
  end;

procedure TFormMain.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
  var Ptr ,tempptr:pointer;
  begin
   if socket.ReceiveLength = 11 then//说明接收完毕
      begin
        GetMem(Ptr,11);//申请11个字节的内存
        socket.ReceiveBuf(Ptr,11);//从Socket读11个字节的内容到ptr指向的内存
        copymemory(tempptr,pchar(ptr),10);//从ptr指向的内存中拷贝10个字节n内容赋值给tempptr
        EdtData.Text:=Pchar(tempptr);
        Lblog.Items.Add(inttostr(pByte(pchar(ptr)+10)^));//进行强制指针类型转换,偏移10个字节指向byte的地址,读出byte的值
        Freemem(Ptr);
      end
   else if socket.ReceiveLength < length(EdtData.Text)then//说明没有接收完毕
      begin
        //此处不知道如何做??
      end;
      
  end;//在执行到这里后,系统提示异常。Access Viloation as Address。。。

procedure TFormMain.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);//此事件不知道为什么没有被触发???
var
  StrErr:string;
begin
  case ErrorEvent of
    eeConnect : StrErr:='不能建立连接';
    eeDisconnect : StrErr:='连接被关闭';
    eeReceive : StrErr:='接收数据出错';
    eeSend : StrErr:='发送数据出错';
    eeAccept: StrErr :='连接产生链入错误';
  else
    StrErr:='连接出错';
  end;
  ErrorCode:=0;
end;

end.
 
这个程序主要是想让Server(非阻塞)和Client(阻塞)运行一个协议:大致的格式如下:
hello word100
我的问题主要有3个:
1、ClientSokcet给ServerSocket发信息,如果只是发送hello word,则程序可以很好的工作。但是如果后面再加上别的控制字,如一个byte类型的整数,则程序在跳出
ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket);这个过程的时候,会出现一个异常 Access Viloation at address。。。
2、如果我的协议头比较长,30到40个字节,是不是不能保证ServerSocket1ClientRead过程一次能接收完毕,我该怎么做?》
3、如果服务器端没有起来,直接ClientSocket.active:=true;时发出现一个异常,我在ClientonError中写了捕捉代码还是不行,后在加入了try excetp还是不行.
程序代码如下
代码:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdAntiFreezeBase, IdAntiFreeze, IdTCPServer,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,strutils,
  ScktComp;

type
  TFormMain = class(TForm)
    GroupBox1: TGroupBox;
    BtnConnect: TButton;
    BtnSend: TButton;
    BtnDisconnect: TButton;
    GroupBox2: TGroupBox;
    BtnStop: TButton;
    BtnStart: TButton;
    Lblog: TListBox;
    EdtHost: TEdit;
    EdtPort: TEdit;
    EdtData: TEdit;
    Button4: TButton;
    ServerSocket1: TServerSocket;
    ClientSocket1: TClientSocket;
   
    procedure BtnConnectClick(Sender: TObject);
    procedure BtnStartClick(Sender: TObject);
    procedure BtnStopClick(Sender: TObject);
    
    procedure AddLogEntry();
    procedure BtnDisconnectClick(Sender: TObject);
    procedure BtnSendClick(Sender: TObject);
    procedure ServerSocket1Accept(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Connecting(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
   
    
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormMain: TFormMain;
  FLogEntry,FReceived:string;

implementation

{$R *.dfm}


procedure TFormMain.BtnConnectClick(Sender: TObject);
begin
Clientsocket1.Address := EdtHost.Text;
ClientSocket1.Port := StrToInt(EdtPort.Text);
try
  ClientSocket1.Active := true;
except
  on E:exception  do
  showmessage('服务端没有监听');//这里的异常也不能被捕捉???
 end;
end;


procedure TFormMain.BtnStartClick(Sender: TObject);
begin
ServerSocket1.Port := StrToInt(EdtPort.Text);
Serversocket1.Active := True;
if serversocket1.Active=true then
begin
BtnStart.Enabled := False;
BtnStop.Enabled := True;
LbLog.Items.Add('服务器已成功启动!');
end
else
begin
BtnStart.Enabled :=true;
BtnStop.Enabled := false;
LbLog.Items.Add('服务器不能正常启动!');
end;
end;

procedure TFormMain.BtnStopClick(Sender: TObject);
begin
try
  Serversocket1.Active := False;
  BtnStart.Enabled := True;
  BtnStop.Enabled := False;
  LbLog.Items.Add('服务器已成功停止!');
except
  showmessage('服务器不能正常停止');
end;
end;

procedure TFormMain.AddLogEntry();
begin
  LbLog.Items.Add(FLogEntry);
end;

procedure TFormMain.BtnDisconnectClick(Sender: TObject);
begin
  ClientSocket1.Active:=false;
  LbLog.Items.Add('同主机 ' + EdtHost.Text + ' 的连接已断开!');
  BtnConnect.Enabled := True;
  BtnSend.Enabled := False;
  BtnDisconnect.Enabled := False;
end; 


procedure TFormMain.BtnSendClick(Sender: TObject);
  var Ptr:pointer;
      sendstr:string;
      SendStrLen:integer;
begin
  SendStr := 'hello word';
  SendStrLen:=length(SendStr);
try
  GetMem(ptr,11);//申请11个Byte
  CopyMemory(Ptr,pchar(sendstr),SendStrLen);//把‘hello word’拷贝到ptr指向的地址,占用10个字节
  pbyte(pchar(ptr)+10)^ :=100;//将指针偏移10个字节,指向第11个字节位置,写入byte类型值100
  LbLog.Items.Add('客户端发送:' + Sendstr);
  ClientSocket1.Socket.SendBuf(ptr,11);//组成一个协议头,发往ServerSocket
  FreeMem(ptr);
except
  LbLog.Items.Add('发送数据失败!');
  ClientSocket1.Active:=false;
  LbLog.Items.Add('同主机 ' + EdtHost.Text + ' 的连接已断开!');
  BtnConnect.Enabled := True;
  BtnSend.Enabled := False;
  BtnDisconnect.Enabled := False;
end;//end try
end;//

procedure TFormMain.ServerSocket1Accept(Sender: TObject;
  Socket: TCustomWinSocket);
  begin
    LbLog.Items.Add('From IP: '+socket.RemoteAddress+' 被接纳');
  end;

procedure TFormMain.ClientSocket1Connecting(Sender: TObject;
  Socket: TCustomWinSocket);
  begin
    Lblog.Items.Add('正在连接'+Edthost.Text+'....');
  end;

procedure TFormMain.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
  begin
    BtnConnect.Enabled := False;
    BtnSend.Enabled := True;
    BtnDisconnect.Enabled := True;
  end;

procedure TFormMain.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
  var Ptr ,tempptr:pointer;
  begin
   if socket.ReceiveLength = 11 then//说明接收完毕
      begin
        GetMem(Ptr,11);//申请11个字节的内存
        socket.ReceiveBuf(Ptr,11);//从Socket读11个字节的内容到ptr指向的内存
        copymemory(tempptr,pchar(ptr),10);//从ptr指向的内存中拷贝10个字节n内容赋值给tempptr
        EdtData.Text:=Pchar(tempptr);
        Lblog.Items.Add(inttostr(pByte(pchar(ptr)+10)^));//进行强制指针类型转换,偏移10个字节指向byte的地址,读出byte的值
        Freemem(Ptr);
      end
   else if socket.ReceiveLength < length(EdtData.Text)then//说明没有接收完毕
      begin
        //此处不知道如何做??
      end;
      
  end;//在执行到这里后,系统提示异常。Access Viloation as Address。。。

procedure TFormMain.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);//此事件不知道为什么没有被触发???
var
  StrErr:string;
begin
  case ErrorEvent of
    eeConnect : StrErr:='不能建立连接';
    eeDisconnect : StrErr:='连接被关闭';
    eeReceive : StrErr:='接收数据出错';
    eeSend : StrErr:='发送数据出错';
    eeAccept: StrErr :='连接产生链入错误';
  else
    StrErr:='连接出错';
  end;
  ErrorCode:=0;
end;

end.
 
[:(]怎么没有人回答我的问题那???
 
ServerSocket和ClientSocket中的错误捕捉方法:
在自己的代码中写一个Socket错误处理过程,然后将该过程的赋值给
ServerSocket或ClientSocket的OnError属性。这样子当Socket发生错误时,就会回调你的错误处理过程,当你处理完后,一定要将ErrorCode设为0,否则,错误提示还会出现。
 
可是我就是在OnError的标准事件中已经写了代码的啊

另外,我如何发送格式不固定的信息,如:
我首先会发一个固定格式的报文头,在报文头里面有报文体的长度,报文体有如下格式:
名称的总数| 第1个名称的长度| 第1个名称|第2个名称的长度| 第2个名称.... 1byte 1byte char类型 1byte char类型 ....
第n个名称长度}第n个名称
1byte Char类型

我在上面的程序中使用GetMem的方法,然后指针偏移,对内存进行赋值.但是有问题,如问题1所述.
 
对数据长度是有限制的
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
686
import
I
后退
顶部