前人用delphi编的服务器用来和VC编的客户端通信,有些不合理的地方,老板让我这个没接触过Delphi的新手修改,有些程序看不通望大牛指导:按文档说明应当是:
服务器与客户端通信时:
服务器端确认后返回值4E4E
客户端每发送1包,等待服务器返回确认。
如果返回0x0E0E,表示数据传送正确,继续下一包;
如果返回0x4545,表示数据传送错误,重新发送这一包。类似以上的关键字,但是我从该句并没有看出相关的东西,后面的一句ClientSocket.SendText('E');这个倒是符合要求 E的ASCII即16进制的45相关语句如下:Begin
While Not Terminated And ClientSocket.Connected Do
begin
Try
//如果没有接受数据,延时10秒后中断连接线程
SocketStream := TWinSocketStream.Create(ClientSocket, 10000);
Try
if Not RecvingClient then
begin
FillChar(FirstData, SizeOf(FirstData), 0);
If SocketStream.Read(FirstData,8) = 0 Then
Begin
ClientSocket.SendText('Timeout on Server'+#13#10);//这句向socket发送的是什么?
sleep(1);
ClientSocket.Close;
Terminate;
End;
CBufRecv:=FirstData;
if JudgeCustomer(CBufRecv) then
begin
ClientSocket.SendBuf(CBufRecv^,2);
//列为已注册用户
InsertClientToTre(ClientSocket.RemoteAddress,FrmMain.TreeView1.Items[0]);
end
else
begin
//列为未知用户
InsertClientToTre(ClientSocket.RemoteAddress,FrmMain.TreeView1.Items[1]); ClientSocket.SendText(Copy(String(FirstData),0,2));//该句发送的是? CBufRecv^:=char(5);
end;
服务器与客户端通信时:
服务器端确认后返回值4E4E
客户端每发送1包,等待服务器返回确认。
如果返回0x0E0E,表示数据传送正确,继续下一包;
如果返回0x4545,表示数据传送错误,重新发送这一包。类似以上的关键字,但是我从该句并没有看出相关的东西,后面的一句ClientSocket.SendText('E');这个倒是符合要求 E的ASCII即16进制的45相关语句如下:Begin
While Not Terminated And ClientSocket.Connected Do
begin
Try
//如果没有接受数据,延时10秒后中断连接线程
SocketStream := TWinSocketStream.Create(ClientSocket, 10000);
Try
if Not RecvingClient then
begin
FillChar(FirstData, SizeOf(FirstData), 0);
If SocketStream.Read(FirstData,8) = 0 Then
Begin
ClientSocket.SendText('Timeout on Server'+#13#10);//这句向socket发送的是什么?
sleep(1);
ClientSocket.Close;
Terminate;
End;
CBufRecv:=FirstData;
if JudgeCustomer(CBufRecv) then
begin
ClientSocket.SendBuf(CBufRecv^,2);
//列为已注册用户
InsertClientToTre(ClientSocket.RemoteAddress,FrmMain.TreeView1.Items[0]);
end
else
begin
//列为未知用户
InsertClientToTre(ClientSocket.RemoteAddress,FrmMain.TreeView1.Items[1]); ClientSocket.SendText(Copy(String(FirstData),0,2));//该句发送的是? CBufRecv^:=char(5);
end;
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, ExtCtrls,WinSock;type
TFileInfo=packed record
FileName:array[0..1024-1] of char;
FileSize:integer;
end;
type
TFrmClient = class(TForm)
Panel1: TPanel;
Memo1: TMemo;
Panel2: TPanel;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
BitBtn4: TBitBtn;
procedure BitBtn3Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
FrmClient: TFrmClient;implementation{$R *.dfm}procedure TFrmClient.BitBtn3Click(Sender: TObject);
begin
close;
end;procedure TFrmClient.BitBtn1Click(Sender: TObject);
var
c:TSocket;
SAddr:TSockAddr;
WSA:TWSAdata;
WSAStatus,len:integer;
FileInfo:TFileInfo;
begin
try
WSAStatus:=WSAStartUP($202,WSA);
if WSAStatus<>0 then
begin
Memo1.Lines.Add('WSAStatus Error');
Exit;
end; c:=Socket(AF_INET,SOCK_STREAM,0);
if c<0 then
begin
Memo1.Lines.Add('Socket Failed');
exit;
end;
SAddr.sin_family:=AF_INET;
SAddr.sin_port:=htons(2007);
SAddr.sin_addr.S_addr:=inet_addr('127.0.0.1');
len:=SizeOf(TSockAddr);
WSAStatus:=connect(c,SAddr,len); if WSAStatus<>0 then
begin
Memo1.Lines.Add('Connect to Error');
exit
end;
Recv(C,FileInfo,SizeOf(TFileInfo),0);
Memo1.Lines.Add('FileName='+FileInfo.FileName+#13#10+'Length='+IntToStr(FileInfo.FileSize));
closesocket(c);
finally
Memo1.Lines.Add('Thread end');
WSACleanUP();
end;
end;end.
下面是服务端监听线程 和工作线程
unit UntWorkThread;interfaceuses
Classes,Winsock,StdCtrls,SysUtils,ComCtrls,idGlobal;type TFileInfo=packed record
FileName:array[0..1024-1] of char;
FileSize:integer;
end;type
TWorkThread = class(TThread) private
FSocket:TSocket;
{ Private declarations }
protected
procedure Execute; override;
procedure SendFile;
public Console:TMemo;
fn:String;
ProgBar:TProgressBar;
property C:TSocket write FSocket;
procedure Disconnect;
end;
var
WorkThread:array [0..10] of TWorkThread;
implementation{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TWorkThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }{ TWorkThread }//------------------------------------------------------------------------------
procedure TWorkThread.Execute;
begin Synchronize(SendFile);
{ Place thread code here }
end;
//------------------------------------------------------------------------------
procedure TWorkThread.SendFile;
const BUFSIZE:integer=1024*2;
var
FHandle,Length:integer;
SendBuf:array [0..49] of char;
FileInfo:TFileInfo;
begin
if Not FileExists(fn) then exit;
FHandle:=FileOpen(fn,fmOpenRead or fmShareDenyNone);
if FHandle<=0 then
begin
Console.Lines.Add('打开文件失败!线程结束');
Disconnect;
exit;
end;
StrCopy(FileInfo.FileName,Pchar(ExtractFileName(fn)));
FileInfo.FileSize:=FileSizeByName(fn);
if FSocket=INVALID_SOCKET then
begin
Console.Lines.Add('INVALID_SOCKET'+IntToStr(FSocket));
end;
Length:=Send(FSocket,FileInfo,SizeOf(TFileInfo),0);
Console.Lines.Add('Send length '+InttoStr(Length));
{ While not Terminated do
begin
Send(FSocket,); end; }
disconnect;
FileClose(FHandle);
end;
//------------------------------------------------------------------------------
procedure TWorkThread.Disconnect;
begin
closesocket(FSocket);end;
end.
工作线程:
unit UntSend;interfaceuses
Classes,Winsock,StdCtrls,SysUtils,ComCtrls,UntWorkThread;type
TListenThread = class(TThread)
private
S,C:TSocket;
SAddr,CAddr:TSockAddr;
WSA:TWSAdata;
WSAStatus:Integer; { Private declarations }
protected
procedure Execute; override;
procedure StartListen;
public
Console:TMemo;
fn:String;
ProgBar:TProgressBar;
procedure StopListen; end;implementation{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure SendFile.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }{ SendFile }const PORT:Integer=2007;
//------------------------------------------------------------------------------
procedure TListenThread.Execute;
begin
{ Place thread code here }
startListen;
Console.Lines.Add('The Thread Stop !');
end;
//------------------------------------------------------------------------------
procedure TListenThread.StartListen;
var
i:integer;
begin
try
WSAStatus:= WSAStartUp($202,WSA);
if WSAStatus<>0 then
begin
Console.Lines.Add('WSAStartUp Failed !');
exit;
end;
Console.Lines.Add('WSAStartUp Successful!'); s:=Socket(AF_INET,SOCK_STREAM,0);
if s<0 then
begin
Console.Lines.Add('Socket Failed');
exit;
end;
Console.Lines.Add('Socket OK!'); SAddr.sin_family:=AF_INET;
SAddr.sin_port:=htons(PORT);
SAddr.sin_addr.S_addr:=INADDR_ANY; WSAStatus:=bind(s,SAddr,sizeof(SAddr));
if WSAStatus<>0 then
begin
Console.Lines.Add('Bind Failed1');
exit;
end;
Console.Lines.Add('Bind OK!'); WSAStatus:=listen(s,5);
if WSAStatus<>0 then
begin
Console.Lines.Add('Listen Failed');
exit;
end;
Console.Lines.Add('Listen OK'+#10+'Server Port'+inttostr(PORT)); WSAStatus:=Sizeof(CAddr); i:=0;
c:=accept(s,@CAddr,@WSAStatus);
Console.Lines.Add('A Client connected'); while true do
begin
WorkThread[i]:=TWorkThread.Create(true);
WorkThread[i].FreeOnTerminate:=true;
WorkThread[i].Console:=Console;
WorkThread[i].fn:=fn;
WorkThread[i].ProgBar:=ProgBar;
WorkThread[i].c:=c;
WorkThread[i].Resume;
if s=INVALID_SOCKET then break;
c:=accept(s,@CAddr,@WSAStatus);
sleep(10);
inc(i);
end;
Console.Lines.Add('The ListenSock Closed!');
finally
Console.Lines.Add('Clean WSADAtA');
WSACleanUP();
end;
end;
//------------------------------------------------------------------------------
procedure TListenThread.StopListen;
begin
closesocket(s);end;
end.