急!急!!!当客户端的clienttype属性选择ctblocking时,服务端的servertype属性是否一定要选择stthreadblocking?(50

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

zhengcw

Unregistered / Unconfirmed
GUEST, unregistred user!
急!急!!!当客户端的clienttype属性选择ctblocking时,服务端的servertype属性是否一定要选择stthreadblocking?(50分)<br />当客户端的clienttype属性选择ctblocking时,服务端的servertype属性是否一定要选择stthreadblocking?
当服务端的servertype属性选择stthreadblocking时,客户端的onread事件中用sendtext发送的
信息,为什么在服务端的onread事件没有执行。
 
不用啊!!!
Server端什么模式都可以,阻塞和非阻塞只是发送数据的方式不一样,没有什么其他的区别!
》》当服务端的servertype属性选择stthreadblocking时,客户端的onread事件中用sendtext发送的
信息,为什么在服务端的onread事件没有执行。
这个时候不能在服务端的ONREAD事件里读数据
应该在ServerSocketGetThread事件里写代码,
 
to 张无忌
还是不行,你说的ServerSocketGetThread事件这是在客户端启动时所触发的,
在发送信息时根本没有运行。这是我的服务程序,你看应该如何操作。


unit dogserver;

interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ScktComp, ExtCtrls, Mask,winsock
;

Type
Tdogserver = Class(TCustomServerSocket)
Private
procedure FServerSocketAccept(Sender: TObject; Socket: TCustomWinSocket);
procedure FServerSocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure FServerSocketError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure FServerSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
procedure FServerSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);

procedure PackData(data:TDataPackage;Var p:array of byte); //数据打包
procedure UnPackData(p:array of byte;Var data:TDataPackage);//数据解包
Public
Function CheckDog :integer;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function netlogin :boolean; //登录
function netlogout :boolean; //退出
end;
var
tcpip :array of string; //存放客户机IP地址的数组
path :string; // 路径
logstatus,maxclientcount :integer;

Const
ServerPort = 1999;
implementation


constructor Tdogserver.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FServerSocket := TServerWinSocket.Create(INVALID_SOCKET);
InitSocket(FServerSocket);

ServerType := stThreadBlocking;
Port := ServerPort;
logstatus := 0;

OnAccept := FServerSocketAccept;
OnClientError := FServerSocketError;
OnClientDisconnect := FServerSocketDisconnect ;
OnClientRead := FServerSocketRead;
onGetThread := FServerSocketGetThread;
end;

destructor Tdogserver.Destroy;
begin
FServerSocket.Free;
inherited Destroy;
end;

function Tdogserver.netlogin: boolean;
var
maxcountstr :string;
i :integer ;
begin
Result := false;

maxclientcount := 80;
setLength(tcpip,maxclientcount);
FServerSocket.ThreadCacheSize := maxclientcount;//设置最大数量
try
port := ServerPort;
Active := True;
Result := true;
logstatus := 1;
Except
result := false;
end;
end;

function Tdogserver.netlogout: boolean;
begin
//关闭服务,退出窗口
Result := false;
if logstatus = 0 then //是否已经断开
exit
else
try
Active := False;
Result := true;
logstatus := 0;
exit;
Except
result := false;
end;
end;

procedure Tdogserver.FServerSocketAccept(Sender: TObject; Socket: TCustomWinSocket);
var
encryptstr,decryptstr :string;
begin
if FServerSocket.ActiveConnections &gt; maxclientcount then //已满则关闭当前连接并发送提示信息。
begin
Socket.sendtext('已经超出服务器的最大限量!');
socket.Close;//如果超出关闭
end
else //没有满则显示并记录
tcpip[FServerSocket.ActiveConnections-1] :=
FServerSocket.Connections[FServerSocket.ActiveConnections-1].RemoteAddress;
end;

procedure Tdogserver.FServerSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
var
receivetcpip :string;
begin
socket.close;
end;
procedure Tdogserver.FServerSocketError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ErrorCode := 0;
FServerSocketDisconnect(sender,socket);
end;
procedure Tdogserver.FServerSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var
decryptstr :string;
begin
//拆包
decryptstr := socket.Receivetext;
end;
procedure Tdogserver.FServerSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
end;
procedure Tdogserver.PackData(data: TDataPackage; var p: array of byte);
begin
copymemory(@p,@data,sizeof(data)); //数据打包
end;
procedure Tdogserver.UnPackData(p: array of byte; var data: TDataPackage);
begin
copymemory(@data,@p,sizeof(data)); //数据解包
end;
end.
 
to 张无忌大侠
这是我的客户端的程序,麻烦你看一看。我比较急的,谢谢!!!
unit clientproc;
interface
uses scktcomp,classes,Forms, Windows, Dialogs, SysUtils, winsock;

type
TclientDogConn =class(TCustomSocket)
Private
FClientSocket: TClientWinSocket;

procedure DoActivate(Value: Boolean); override;
procedure FClientSocketDisconnect(Sender: TObject; Socket: TCustomWinSocket); {断开连接}
procedure FClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer); {连接错误}
procedure FClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);{读取服务器上的数据}
procedure sendmessage(messagesend: string); {发送信息}
function receiveout :string; {返回客户端收到的服务器的信息}
public
Constructor Create(AOwner: TComponent); override; {创建}
Destructor Destroy; override; {析构}
function sendandreceivemessage(messagesend :string) :string;{发送消息并返回信息}
function netlogin :Boolean; //登录
function netlogout :Boolean; //退出
end;
var
logstatus :integer;
//logstatus是登录的状态

Const portclient:integer=1999;

implementation

constructor TClientDogConn.create(AOwner: TComponent);{创建}
begin
inherited Create(Aowner);
Cfrm := TClientForm.Create(nil);
try
FClientSocket := TClientWinSocket.Create(INVALID_SOCKET);
except //捕捉出错信息
on e:exception do
showmessage(e.message);
end;
InitSocket(FClientSocket);


//全局变量赋值
tcpip := '192.192.192.111';

OnError := FClientSocketError;
OnDisconnect := Fclientsocketdisconnect;
OnRead := FClientSocketRead;
end;

Destructor TClientDogConn.Destroy; {析构}
begin
FClientSocket.Free;
inherited Destroy;
end;

function TClientDogConn.netlogin :boolean; //登录
var
i :integer ;
begin
result := false;
//判断端口号有没有设置
try
with FClientSocket do
begin
Host := tcpip;
port := portclient;
ClientType := ctBlocking;
Active := True;
end;
logstatus := 1;//已经登录了
result := true;
except
on e:exception do
showmessage(e.message);
end;
end;

function TClientDogConn.netlogout:boolean; //退出
begin
result := true;
if logstatus=0 then//是否已经断开
exit
else
try
begin
logstatus := 0;
active := false;
end;
except
result := false;
end;
end;

procedure TclientDogConn.DoActivate(Value: Boolean); //
begin
if (Value &lt;&gt; FClientSocket.Connected) and not (csDesigning in ComponentState) then
begin
if FClientSocket.Connected then
FClientSocket.Disconnect(FClientSocket.SocketHandle)
else FClientSocket.Open(Host,Address,Service,Port);//当服务器没开时客户端连接就出错的地方
end;
end;

procedure TclientDogConn.FClientSocketError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ErrorCode := 0;
logstatus := 0;
end;

procedure TclientDogConn.FClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
active := false;
logstatus := 0;
end;

procedure TclientDogConn.FClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var
receive :string;
begin
receive :=socket.Receivetext; //接收数据
//有一段判别是否是服务器要退出或超出数量的程序没写

end;

function TclientDogConn.sendandreceivemessage(messagesend: string): string;
begin
sendmessage(messagesend);
result := receiveout();
end;

procedure TclientDogConn.sendmessage(messagesend: string); {发送信息}
begin
FClientSocket.sendtext(messagesend);
end;

function TclientDogConn.receiveout :string; {返回客户端收到的服务器的信息}
begin
if FClientSocket.Connected then
result := fclientsocket.receivetext;
else
result := '连接失败!';
end;
end.
 
当你把服务端设置成stthreadblocking的阻塞方式的时候,OnRead根本不会被触发,OnRead是
在非阻塞的异步的时候才会被触发.所以你上面的代码大部分是无效的,正确的方法(阻塞)是
定义一个ClientThread的线程类,在ServerSocketGetThread的时候创建一个线程,处理客户端
请求..这样就可以支持多个客户端同时连接和收发封包. 至于客户端,用非阻塞的方式就可以了.
 
我和bluely的办法一样,就是在ServerSocketGetThread创建线程~~~~~~~~~
 
to bluely,张无忌:
“ 客户端,用非阻塞的方式就可以了”?我就这样,什么服务器端收到的stream.size是0.
我的代码如下:
客户端:
unit main2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls, ComCtrls;

type
TForm1 = class(TForm)
nmg_objClientSocket: TClientSocket;
Button2: TButton;
Edit1: TEdit;
StatusBar1: TStatusBar;
OpenDialog1: TOpenDialog;
procedure Button2Click(Sender: TObject);
procedure nmg_objClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure nmg_objClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure nmg_objClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
private
stream : TMemoryStream; //定义内存流,其实用文件流也可以
size,count : integer; //文件大小
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
nmg_blnServerReady:boolean;

implementation

{$R *.dfm}

procedure TForm1.nmg_objClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected to '+Socket.RemoteAddress;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
nmg_objClientSocket.Address := Edit1.Text;
//nmg_objClientSocket.Port:=2000;
nmg_objClientSocket.open;
end;

procedure TForm1.nmg_objClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var
rcvtxt : string;
buf : array [1..2048] of char;
left : integer;
begin
rcvtxt := Socket.ReceiveText;
left := size - count; //未读字节数
if AnsiPos('go',rcvtxt)=1 then //收到响应则发
begin
StatusBar1.SimpleText := '正在传文件。'+Format('%3.0f',[count/size * 100]);
if sizeof(buf)&lt;left then //若满一块则读一块
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else //不满则发剩余的
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
socket.Close;
end;
end;

if AnsiPos('yesReady',rcvtxt)=1 then //收到响应则发
begin
stream := TMemoryStream.Create;
//if OpenDialog1.Execute then
//begin
stream.LoadFromFile('I:/a.exe');
size := stream.Size; //获得文件大小
StatusBar1.SimpleText := '准备传文件。文件大小:'+inttostr(size);
count := 0;
//nmg_objClientSocket.Socket.SendText(); //先发送大小
Socket.SendText(inttostr(size));
//end;
end;

if AnsiPos('noReady',rcvtxt)=1 then //收到响应则发
begin
showmessage('noready');
nmg_blnServerReady := false;
Socket.Close;
end;
end;

procedure TForm1.nmg_objClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'disconnect';
end;

end.

服务器端:
unit server3;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, ComCtrls, StdCtrls;

type
TdealThread = class(TServerClientThread)
private
protected
procedure ClientExecute; override;
public
thr:tserverclientwinsocket;
end;

type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
StatusBar1: TStatusBar;
SaveDialog1: TSaveDialog;
nmg_txtMonitorDir: TEdit;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1GetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
private
{ Private declarations }
Tof : file;
size,count :integer;
public
{ Public declarations }
end;


var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
//ServerSocket1.Port := 2000;
ServerSocket1.Active := true;
StatusBar1.SimpleText := 'Listening...';
end;

procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected from '+ Socket.RemoteAddress;
if nmg_txtMonitorDir.Text = '' then
Socket.SendText('noReady')
else
Socket.SendText('yesReady');
end;

procedure TForm1.ServerSocket1GetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread);
var
myt:tdealthread;
begin
myt:=tdealthread.Create(false,clientsocket) ;//这个
myt.thr :=clientsocket;
socketthread:=myt;
end;
procedure TdealThread.ClientExecute;
var
Stream : TWinSocketStream;
Buf : array[1 .. 2048] of Char;
senddata:ansistring;
revData,fileName:string;
left,len : integer;
begin
{ make sure connection is active }
while (not Terminated) and ClientSocket.Connected do
begin
try
Stream := TWinSocketStream.Create(ClientSocket, 60000);
try
FillChar(Buf, SizeOf(Buf), 0); { initialize the buffer }
{ give the client 60 seconds to start writing }
if Stream.WaitForData(60000) then
begin
if Stream.Read(Buf, SizeOf(Buf)) = 0 then { if can't read in 60 seconds }
ClientSocket.Close; { close the connection }
len := Stream.Size;
//if len = 1 then
if len &lt; 10 then
begin
Stream.Read(Buf, SizeOf(Buf));
Repeat
fileName := 'c:/temp/'+IntToStr(Random(10000))+'.exe';
Until not FileExists(fileName);
AssignFile(Form1.ToF, fileName);
Rewrite(Form1.ToF, 1);
ClientSocket.SendText('go');
end
else
begin
left := Form1.size - Form1.count; //未写的字节数
if sizeof(buf)&lt;left then //满一块则写一块
begin
Stream.Read(Buf, SizeOf(Buf));
BlockWrite(Form1.Tof,buf,sizeof(buf));
Form1.count := Form1.count + sizeof(buf);
ClientSocket.SendText('go');
end
else //否则写剩余字节数
begin
Stream.Read(Buf, SizeOf(Buf));
BlockWrite(Form1.Tof,buf,left);
CloseFile(Form1.Tof);
ClientSocket.Close;
end;
end;
end
else
ClientSocket.Close; { if client doesn't start, close }
finally
Stream.Free;
end;
except
HandleException;
end;

end;
end;
end.

我的代码问题出在哪?
 
后退
顶部