一个星期了还没有解决好的问题,分多少你说了算(0分)

  • 主题发起人 yourkeychen
  • 开始时间
Y

yourkeychen

Unregistered / Unconfirmed
GUEST, unregistred user!
------------------------------以下是服务端的程序-----------------------------
unit test_server;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, SUIButton, StdCtrls, SUIEdit, DBXpress, DB, SqlExpr,
IdBaseComponent, IdComponent, IdTCPServer, ScktComp, ComCtrls, ExtCtrls,
Grids, DBGrids, WinSkinData, WinSkinForm, Buttons;

type
TForm1 = class(TForm)
Panel1: TPanel;
StatusBar1: TStatusBar;
ServerSocket1: TServerSocket;
Memo1: TMemo;
DBGrid1: TDBGrid;
TreeView1: TTreeView;
WinSkinForm1: TWinSkinForm;
SkinData1: TSkinData;
ListBox1: TListBox;
EdtVodPath: TEdit;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
ProgressBar1: TProgressBar;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure BitBtn1Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn3Click(Sender: TObject);
private
{ Private declarations }
public

{ Public declarations }
end;

const
UniqueAppstr='I_AM_UNIQUE_APP';
PASSID = '!$@%*#^('; //用户名和密码传送前导标志
FSIZEID = '~!@#$%'; //文件长度前导标志
MAX_LEN = 2048;
ENDID = '@@@12@13@14@@41@31@21@@@'; //24位传输结束标志
bufsize = 1460; //缓冲区大小

var
Form1: TForm1;

function checkpass(userinfo,passinfo:string):boolean;
//验证口令字

procedure DirToTreeView(ATreeView: TTreeView; ADirectory: string;
ARoot: TTreeNode; AIncludeFiles: Boolean);
//把指定的目录返回到 TreeView 结构中

procedure SendVodDir;
//发送影片目录文件到客户端

implementation

uses U_DataModule1, U_adduser;
var
total_user : integer=0; //在线用户合计数
DefaultHost : string = '192.168.0.2'; //默认主机地址
DefaultPort : integer = 1009; //默认主机端口
CHECKID : string = ''; //验证后的标志 'passok' 为通过,其它为没通过
VODDIR : string = 'd:/movie'; //默认影片目录

iSen : integer = 0; //iSen发送出去的长度
iSize : integer = 0; //文件长度 最好是全局变量
buf:array[1..MAX_LEN]of char;
senlen : integer = 0; //每次应该发送的长度
ret : integer = 0; //实际发送的文件长度
filen : file; //最好是全局变量
filelong :int64;

{$R *.dfm}




procedure TForm1.FormCreate(Sender: TObject);
var
DirRoot : TTreenode;
begin
// 程序开始运行时激活服务器端Socket
ServerSocket1.Active := false;
ServerSocket1.Port := DefaultPort;
ServerSocket1.Active:= true;

Statusbar1.Panels.Items[0].Text:='服务器启动.主机名:'+ServerSocket1.Socket.LocalHost+' 监听端口:'+inttostr(ServerSocket1.Port);
self.Caption:=Statusbar1.Panels.Items[0].Text;
Application.Title:=Statusbar1.Panels.Items[0].Text;
Statusbar1.Panels.Items[1].Text := '在线用户数: '+IntToStr(ServerSocket1.Socket.ActiveConnections);

Statusbar1.Panels.Items[2].Text := '你的登录时间为:' + formatdatetime('yyyy年mm月dd日 hh:mm:ss',now);

DirRoot := TreeView1.Items.Add(nil, 'DirRoot');
//新建TreeView根结点

DirToTreeView(Treeview1,VODDIR,DirRoot,true);
//根据电影目录生成TreeView结构

TreeView1.FullExpand;
TreeView1.SaveToFile('c:/voddir.vod');
// filelong := filen.Size;
//上面两句,我本想将TreeView存入一个文件,然后将这个文件发过去的,但没做好
assignfile(filen, 'c:/voddir.vod');
reset(filen,1);
filelong:=filesize(filen);
closefile(filen);
// TreeView1.FullCollapse;


end;


procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
Var
strIp,strHost:string;
Count:Integer;
begin
strIp:=Socket.RemoteAddress;
strHost:=Socket.RemoteHost;
Memo1.Lines.Add('当前登录用户');
Memo1.Lines.add(#9'SocketID:'+Inttostr(Socket.SocketHandle));
with DataModule1 do
begin
SqlDataSet1.Active := false;
SqlDataSet1.CommandType := ctQuery;
SqlDataSet1.CommandText := 'insert into logs (ipaddr,socketid,computer,logintime) values ('
+ '''' + strIP + '''' + ',' + '''' + inttostr(socket.socketHandle) + '''' + ',' + '''' + strHost + '''' + ',' + '''' + formatdatetime('yyyy-mm-dd hh:mm:ss',now) + '''' + ')';

//日志记录内容:当前客户机IP地址、SOCKET标识、计算机名、登录时间、

// showmessage(sqldataset1.CommandText); //调试,用于显示Sql语句
try
SqlDataSet1.ExecSQL(false);
// SqlDataSet1.Refresh;
except on E:exception do
begin
Messagebox(0,pchar('Log日志记录错误!'),pchar('提示'),MB_OK + MB_IconError + MB_SYSTEMMODAL);
// FlashWindow(form1.Handle,true);
exit;
end;
end;
end;
// Combox1.Items.Add(Inttostr(Socket.SocketHandle));

Memo1.lines.add(#9'IP地址:'+strIp);
Memo1.Lines.Add(#9'主机名:'+strHost);
Count := ServerSocket1.Socket.ActiveConnections; //Count得到当前连接的用户数
Statusbar1.Panels.Items[1].Text := '在线用户: '+IntToStr(Count);

end;


procedure sendvoddir;
var
fs: TFileStream;
s: string;
buf: array[0..bufsize-1] of char;
i, n, pos: integer;
ret, nBytes, nLeft, idx: integer;
begin
n := 0;
fs := TFileStream.Create('c:/voddir.vod', fmOpenRead); //打开一个文件
if not form1.ServerSocket1.Socket.Connections[0].Connected then exit; //如果客户端没有连接,那么退出
while fs.Position < fs.Size do //如果文件指针位置小于文件长度,那么说明还有数据要继续发送
begin
if (fs.Size - fs.Position) < bufsize then //判断是否是最后一次发送(因为最后一次流文件的长度可能不够1400字节)
pos := fs.Size - fs.Position //如果是,那么发送剩余的字节数
else
pos := bufsize; //否则发送1400个字节
FillChar(buf, bufsize, 0); //清零要发送的缓冲区
fs.ReadBuffer(buf, pos); //把文件内容读入缓冲区

//下面的while是保证数据能够正确发送的关键,可以防止数据缓冲区丢失数据
nLeft := bufsize;
idx := 0;
while nLeft > 0 do
begin
ret := form1.ServerSocket1.Socket.Connections[0].SendBuf(buf[idx], nLeft); //发送文件内容
if ret = -1 then //如果返回-1,说明发送错误
begin
//raise exception.Create('Sendbuf error'); //你也可以根据数据是否重要来决定是中断发送,
break; //还是跳过此次发送,而继续下次发送
end;
inc(idx, ret);
dec(nLeft, ret);
end;

inc(n); //发送次数,和客户端的RecvTotal对应
sleep(10);
end;

fs.Free;
end;


procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
///////////////////////////////////////////////////////////////////////////////
var
p:pchar;
length:longint;
Count,i:Integer;
tmpuser,tmppass : string;
tmpsocket : TCustomWinSocket;

begin
///////////////////////////////////////////////////////////////////////////////
p:=nil;
while socket.ReceiveLength > 0 do //如果接收缓冲区不为空,表示有信息收到
begin
length:=socket.receivelength; //记录接收缓冲区长度
Getmem(p,length); //为接收分配内存
TRY
socket.ReceiveBuf(p^,socket.receivelength); //接收到P指针的缓冲区中
Count:=ServerSocket1.Socket.ActiveConnections; //总的用户数加 1
// for i:=0 to Count-1 do
// ServerSocket1.Socket.Connections.SendBuf(p^,length);
//循环将消息发送给每个客户端

//如果接收到的是用户名和密码验证字串就进行验证
// showmessage('passid is :' + passid );
if (pos(passid,strpas(p)) > 0) and (length > 38) then
//用户名、密码验证前导标志8位,用户名15位,密码15位,共38位
begin
tmpuser := trimright(copy(strpas(p),9,15));
//取用户名

tmppass := trimright(copy(strpas(p),24,15));
//取口令字

// showmessage('user:' + tmpuser + ' ' + 'passwd:' + tmppass);
if checkpass(tmpuser,tmppass) //检查用户名和口令字是否符合
then
CHECKID := 'passok' //验证通过
else
begin
CHECKID := '123456'; //验证不通过
end;

socket.SendText(PASSID + CHECKID + FSIZEID + inttostr(Filelong) + #13#10);
if CHECKID = 'passok' then
sleep(100); //为了怕上次传输的合在一起,先暂停一下,但没有效果
SendVodDir;
//发送验证消息给客户端

end;

FINALLY
FreeMem(p);
END;
end;
end;

//当连接被接受的时候进行的处理
procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
var
Tempstr:pchar;
begin
TempStr:=pchar('欢迎登陆服务器 '#13#10);
// socket.SendText(TempStr);
//通常在这里需要处理一些什么事情
end;

function checkpass(userinfo,passinfo:string):boolean;
//对接收到的用户名和密码信息到数据中进行验证
begin
with DataModule1 do
begin
sqlqry_users.Active := false;
sqlqry_users.SQL.Add('select * from users ');
// where name=' + '''' + sqlqry_users.Params.ParamByName('name').Value + '''' + ' and passwd=' + '''' + sqlqry_users.Params.ParamByName('passwd').Value +'''';
sqlqry_users.Open;

//这里是在上面查询的时候加参数呢是在查询结果出来后再来查找适合的结果,哪种好,效率更高,个人倾向第一种

if sqlqry_users.Locate('name;passwd',VarArrayOf([userinfo,passinfo]),[loPartialKey]) then
//对指定的用户名和口令字在用户数据表中进行查找

begin //用户口令验证成功的处理
// showmessage('pass');
Result := true;
end
else
begin //用户口令验证失败的处理
// showmessage('not pass');
Result := false;
end;
end;
end;

//当出现Socket连接错误时进行的处理
procedure TForm1.ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
//错误判断
Case ErrorCode Of
10054:Memo1.lines.add('连接被用户重置.');
Else
Memo1.Lines.Add('发生Socket错误,错误代码:'+InttoStr(errorCode));
// 显示错误码
End;
ErrorCode:=0;
Socket.Close;
end;


//当断开连接时的处理
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
Var
Count:Integer;
// IDIndex:Integer;
begin
Memo1.Lines.add('用户离线');
Memo1.Lines.add(' SocketID:'+Inttostr(Socket.SocketHandle));

// IDIndex:=Combox1.Items.IndexOf( Inttostr(Socket.SocketHandle));
// Combox1.Items.Delete(IDIndex);

//该事件在用户离开前发生
Count := ServerSocket1.Socket.ActiveConnections - 1; //当前用户总数减1
Statusbar1.Panels.Items[1].Text := '在线用户:' + Inttostr(Count); //更新状态栏

//将用户离线的时间登记到数据库中

end;


//将指定的目录及子目录下的文件信息返回到TreeView中
procedure DirToTreeView(ATreeView: TTreeView; ADirectory: string;
ARoot: TTreeNode; AIncludeFiles: Boolean);
//------------------------------------------------------------------------
//参数信息 :// 第一个是一个TreeView对象
// 第二个是指定的要取的目录名字
// 第三个是根结点的名字
// 第四个是指明是否包含文件还是只包含目录
//用法及调用格式
// DirRoot := TreeView1.Items.Add(nil, 'DirRoot');
// DirToTreeView(Treeview1,'d:/work',DirRoot,true);
//-------------------------------------------------------------------------
var
SearchRec : TSearchRec;
ItemTemp : TTreeNode;
begin
with ATreeView.Items do
try
BeginUpdate; //开始更新,使用BeginUpdate会使效率更高
if ADirectory[Length(ADirectory)] <> '/' then
ADirectory := ADirectory +'/';

if FindFirst(ADirectory + '*.*', faDirectory, SearchRec) = 0 then
begin
repeat
if (SearchRec.Attr and faDirectory = faDirectory) and (SearchRec.Name[1] <> '.') then
begin
if (SearchRec.Attr and faDirectory > 0) then
ARoot := AddChild(ARoot, SearchRec.Name);
ItemTemp := ARoot.Parent;
DirToTreeView(ATreeView, ADirectory + SearchRec.Name, ARoot, AIncludeFiles);
ARoot := ItemTemp;
end
else if AIncludeFiles then
if SearchRec.Name[1] <> '.' then
AddChild(ARoot, SearchRec.Name);
until FindNext(SearchRec) <> 0;
FindClose(SearchRec);
end;
finally
EndUpdate; //结束更新
end;
end;


procedure TForm1.BitBtn1Click(Sender: TObject);
begin
VODDIR := EdtVodPath.Text;
DirToTreeView(Treeview1,VODDIR,self.TreeView1.GetNodeAt(0,0),true);
//根据电影目录生成TreeView结构
end;

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
TreeView1.FullExpand;
end;

procedure TForm1.BitBtn3Click(Sender: TObject);
begin
TreeView1.FullCollapse;
end;

end.

------------------------------以上是服务端的程序-----------------------------
 
---------------------------------以下是客户的程序----------------------------
unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, {SUITitleBar,} StdCtrls, {SUIMemo, SUIEdit,} ExtCtrls,
{SUIImagePanel,} ComCtrls,{ SUITreeView, SUIButton, }Menus,{ SUIPopupMenu,}
LHRSoft_RealOne, DBCtrls, Mask, ScktComp, Buttons,
WinSkinForm, WinSkinData {ShellCtrls, SUIEdit};

type
Tfm_main = class(TForm)
LHRSoft_RealOne1: TLHRSoft_RealOne;
// suiEdtClk: TsuiEdit;
StatusBar1: TStatusBar;
Bevel1: TBevel;
Bevel2: TBevel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
Label10: TLabel;
Label11: TLabel;
Bevel3: TBevel;
Bevel4: TBevel;
Bevel5: TBevel;
Bevel6: TBevel;
Bevel7: TBevel;
Panel1: TPanel;
DBEdit1: TDBEdit;
DBEdit2: TDBEdit;
DBEdit3: TDBEdit;
DBEdit4: TDBEdit;
DBEdit5: TDBEdit;
DBEdit6: TDBEdit;
DBEdit7: TDBEdit;
DBEdit8: TDBEdit;
DBEdit9: TDBEdit;
DBImage1: TDBImage;
DBEdit10: TDBEdit;
Label12: TLabel;
DBMemo1: TDBMemo;
ClientSocket1: TClientSocket;
Memo1: TMemo;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
BitBtn4: TBitBtn;
BitBtnManager: TBitBtn;
Edit1: TEdit;
Edit2: TEdit;
DBNavigator1: TDBNavigator;
SkinData1: TSkinData;
WinSkinForm1: TWinSkinForm;
TreeView1: TTreeView;
BitBtn5: TBitBtn;
BitBtn6: TBitBtn;
// procedure ShellTreeView1Editing(Sender: TObject; Node: TTreeNode;
// var AllowEdit: Boolean);
// procedure ShellTreeView1DblClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure BitBtn4Click(Sender: TObject);
procedure BitBtnManagerClick(Sender: TObject);
procedure ClientSocket1Connecting(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Lookup(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Write(Sender: TObject;
Socket: TCustomWinSocket);
procedure BitBtn2Click(Sender: TObject);
procedure TreeView1DblClick(Sender: TObject);
procedure BitBtn5Click(Sender: TObject);
procedure BitBtn6Click(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

const
UniqueAppstr='I_AM_UNIQUE_APP';
PASSID = '!$@%*#^('; //用户口令字前导标志
FSIZEID = '~!@#$%@~'; //文件大小前导标志
// DIRID = '!@#$%^~*';
DIRID = 'NODE:';
DefaultHost = '192.168.0.2'; //缺省远程主机地址
DefaultPort = 1009; //缺省远程主机端口
DefaultWEB = 'http://61.175.206.162:1981/'; //缺省播放主机WEB地址及端口
bufsize = 1460; //接收缓冲区
var
MessageID:Integer;
Wproc:TFNWndProc;
MutHandle:Thandle;
fm_main: Tfm_main;
Have_RealPlay : boolean; //RealPlay有无的标志
TotalLen : integer; //总计的接收字节数
VodFile : string = ''; //需要播放的影片路径及名称,相对于TreeView树目录

pwdstr : string = 'passok'; //密码验证通过标志
len : integer;
temp : string;
filem : TFileStream; //filem是一个文件流,最好是全局变量
Alllen : integer = 0; //接收到的文件总长度
SaveFs: TFileStream;

procedure ReveiceVodDir;


implementation

uses u_adddir, U_play, U_login, u_addmovie, U_DataModule1,u_ManagerSelect,
U_sfyz;

{$R *.dfm}


procedure Tfm_main.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
var
Str: String;
relong:integer;
begin
while Socket.ReceiveLength > 0 do // while 1
begin

SetLength(Str,Socket.ReceiveLength);
Socket.ReceiveBuf(str[1],socket.ReceiveLength);
relong := socket.ReceiveLength; //记录缓冲区长度

//计算数据长度
TotalLen := TotalLen + relong; //记录总的接收字节数,即再加上现在收到的长度
Statusbar1.Panels.Items[1].Text := '总共接收(Byte): ' + IntToStr(TotalLen);
Statusbar1.Update();

//如果接收到的字串不为空并且打头的是用户名、密码标志,进入
if (length(str) > length(PASSID)) and SameText(PASSID,Copy(Str,1,length(PASSID))) then
//接收到的是用户口令验证信息
begin
Showmessage('接收到的验证串是:' + Str + ' 长度是:' + inttostr(length(str)));

//如果接收到的验证结果为CHECKID,则验证通过
if copy(str,length(PASSID) + 1,length(CHECKID)) = CHECKID then
begin
fm_sfyz.Hide;
login;
end
else //否则验证不通过
begin
showmessage('user name or password no match!');
// ClientSocket1.Socket.Disconnect(inttostr(socket.SocketHandle));
fm_main.Hide;
fm_sfyz.Show;
end
end //结束验证
else //否则收到的是目录文件
if (length(str) > length(FSIZEID)) and SameText(FSIZEID,Copy(Str,1,length(PASSID))) then
begin
ReveiceVodDir; //接收目录文件
TreeView1.LoadFromStream(SaveFs); //生成目录树
end;
end;
end;

procedure ReveiceVodDir;
var
recvbuff: array [0..bufsize-1] of char;
ret, nLeft, idx: integer;
begin
//其实读数据是写数据的逆向操作,你可以跟Sendbuff部分对照来看
FillChar(recvbuff, bufsize, 0);
nLeft := bufsize;
idx := 0;
while nLeft > 0 do
begin
ret := fm_main.ClientSocket1.socket.ReceiveBuf(recvbuff[idx], nLeft);
if ret = -1 then break;
inc(idx, ret);
dec(nLeft, ret);
end;
if recvbuff = '√' then //如果是文件已经传完的标志,
SaveFs.Free //那么结束文件
else
SaveFS.WriteBuffer(recvbuff, bufsize); //否则把接收的数据写入流文件
inc(TotalLen);
end;


//当主窗体创建时需要处理的工作
procedure Tfm_main.FormCreate(Sender: TObject);

begin
ClientSocket1.Active := false;
ClientSocket1.Host := '192.168.0.2'; //设置缺省主机地址
// DefaultHost;
ClientSocket1.port := 1009; //设置缺省主机端口
// DefaultPort;
ClientSocket1.Active := true;
SaveFS := TFileStream.Create('test.tmp', fmCreate); //建立一个新文件
TotalLen:=0;

////////////////////////////////////////
//下面是对RealOne Player播放组件的判断//
////////////////////////////////////////
if LHRSoft_RealOne1.isSetRealOne then
//如果系统已经安装RealOne Play则调用系统的播放器
begin
Have_RealPlay := true;
end
else
//如果系统没有安装RealOne Play则用内嵌的播放器
begin
LHRSoft_RealOne1.Load;
Have_RealPlay := false;
// showmessage('本机未安装RealOne Player播放器,使用内嵌!');
end;
//--------------------------------判断完毕-----------------------//

end;

//当主窗体关闭时需要处理的工作
procedure Tfm_main.FormClose(Sender: TObject; var Action: TCloseAction);
var
Hwnd:Thandle;
begin
Hwnd:=FindWindow('Tfm_play','fm_play');

if Hwnd <> 0 //如果找到fm_play窗体,即表示正在播放
then
begin
showmessage ('程序还在播放,不能退出');
Action := caNone;
end
else //如果没找到,表示没有现行播放文件,则可以退出
begin
if not Have_RealPlay then
LHRSoft_RealOne1.UnLoad; //如果使用的是内嵌的RealPlay 则退出时卸载控件
showmessage('内嵌播放引擎已经卸载!');
Application.Terminate;
end;
end;


//当主窗体关闭退出时,进行确认
procedure Tfm_main.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Application.MessageBox('确认要退出吗?','询问',MB_YESNO) = IDYES
then CanClose := True
else CanClose := false;
end;

//当客户端连接成功时的处理
procedure Tfm_main.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
//-----------------------------------------------------------------------
//生成和调用身份验证窗口
if fm_sfyz = nil then fm_sfyz := Tfm_sfyz.Create(Application);
fm_main.Hide;
fm_sfyz.ShowModal;
//------------------------------------------------------------------------
Statusbar1.Panels.Items[0].Text:='接受连接'; //改变状态栏信息
Statusbar1.Panels.items[1].text:='';
end;

//当客户端断开的时候处理的工作
procedure Tfm_main.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Statusbar1.Panels.Items[0].Text:='关闭与主机的连接'; //改变状态栏信息
Statusbar1.Panels.Items[1].Text:='';
Memo1.Lines.Clear;
end;

//当连接发生错误的时候进行的处理
procedure Tfm_main.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
exit;
end;


//退出按键的处理
procedure Tfm_main.BitBtn4Click(Sender: TObject);
begin
Application.Terminate;
end;

//管理模块进入的按钮处理模块
procedure Tfm_main.BitBtnManagerClick(Sender: TObject);
begin
if fmManagerSelect = nil then fmManagerSelect := TfmManagerSelect.Create(Application);
fm_main.Hide;
fmManagerSelect.Show;

end;

procedure Tfm_main.ClientSocket1Connecting(Sender: TObject;
Socket: TCustomWinSocket);
begin
// showmessage('OnConnecting..........');
//这里一般处理什么事情
end;

procedure Tfm_main.ClientSocket1Lookup(Sender: TObject;
Socket: TCustomWinSocket);
begin
// showmessage('OnLookup..............');
//这里一般处理什么事情
end;

procedure Tfm_main.ClientSocket1Write(Sender: TObject;
Socket: TCustomWinSocket);
begin
// Showmessage('OnWrite................');
//这里一般处理什么事情
end;


procedure Tfm_main.BitBtn2Click(Sender: TObject);
begin
if fm_play = nil then fm_play := Tfm_play.Create(application);

VodFile := TreeView1.Selected.GetNamePath; //要得到TreeView选定的文件名是否这样处理
showmessage('VodFile is :' + VodFile);
fm_play.RealAudio1.Source := WideString(DefaultWeb + VodFile);
// 这是播放的方式,用URL的方式。
fm_play.RealAudio1.DoPlay; //开始播放
fm_main.Hide; //播放开始,隐藏主窗体
fm_play.Show;

end;

procedure Tfm_main.TreeView1DblClick(Sender: TObject);
begin
VodFile := TreeView1.Selected.Text; //要得到TreeView选定的文件名是否这样处理
if fm_play = nil then fm_play := Tfm_play.Create(application);
fm_play.RealAudio1.Source := WideString(DefaultWeb + VodFile);
fm_play.RealAudio1.DoPlay; //开始播放
fm_main.Hide; //播放开始,隐藏主窗体
fm_play.Show;

end;

procedure Tfm_main.BitBtn5Click(Sender: TObject);
begin
TreeView1.FullExpand;
end;

procedure Tfm_main.BitBtn6Click(Sender: TObject);
begin
TreeView1.FullCollapse;
end;

end.
---------------------------------以上是客户的程序----------------------------
 
---------------------------这个是和客户端发送有点关联的程序-------------------

unit U_sfyz; //密码验证并发送验证结果

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, SUIButton, StdCtrls, SUIURLLabel, SUIEdit, ExtCtrls,
SUIImagePanel, SUIGroupBox, SUIRadioGroup, Buttons,Db, WinSkinForm;

type
Tfm_sfyz = class(TForm)
EdtUser: TEdit;
EdtPwd: TEdit;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
WinSkinForm1: TWinSkinForm;
Label1: TLabel;
Label2: TLabel;
// procedure BitBtn1Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

const
CHECKID = 'passok';
PASSID = '!$@%*#^(';

var
fm_sfyz: Tfm_sfyz;
procedure checkpass;
procedure login;
function blank(num:integer):string;

implementation



uses U_login, U_DataModule1, main;



{$R *.dfm}


procedure login;
begin
fm_sfyz.Hide;
// fm_sfyz.Free;
if fm_login = nil then fm_login := Tfm_login.Create(application);
fm_login.ShowModal;
end;

function blank(num:integer):string;
var
i : integer;
str : string;
begin
for i := 1 to num do
str := str + ' ';
Result := str;
end;

procedure checkpass;
var
// pt : pchar;
// strlong : integer;
tmpuser : string;
tmppass : string;
tmpuspa : string;
begin

//组合用户名和口令发送到服务端

tmpuser := trim(trimright(fm_sfyz.EdtUser.Text));
if length(tmpuser) < 15 then
tmpuser := tmpuser + blank(15 - length(tmpuser));
tmppass := trim(trimright(fm_sfyz.EdtPwd.Text));
if length(tmppass) < 15 then
tmppass := tmppass + blank(15 - length(tmppass));
tmpuspa := tmpuser + tmppass;

fm_main.ClientSocket1.Socket.SendText(PASSID + tmpuspa + #13#10);
//组合用户名及口令字并发送完毕

end;

procedure Tfm_sfyz.BitBtn2Click(Sender: TObject);
begin
close;
Application.Terminate
end;

procedure Tfm_sfyz.BitBtn1Click(Sender: TObject);
begin
checkpass;
end;
end.

---------------------------这个是和客户端发送有点关联的程序-------------------
 
我现在的问题是:
  服务端发送的密码验证信息为什么老是和我要传送的文件合在一起了?我用了#13#10也不能将他们分开?
  我的客户端该如何做才能正确接收我的验证信息和目录文件?事实我的密码验证信息是可以收到的,就是这个传过来的目录文件不能正确收到。我试验的这个文件大概只有几百K左右。
  请客位仔细帮我分析一下我程序中的不足之处和我该做如何改进和变革。谢谢大家了。
分数大写答完了自己定,我一定给。
 
太长了,真的没耐心看完,等我有心情的时候吧!
 
实在是太长了,帮你顶一下
 
服务端发送的密码验证信息为什么老是和我要传送的文件合在一起了?我用了#13#10也不能将他们分开?
//你判断他是密码信息以后虽然做了密码信息的处理,但是处理玩之后又接着做传送文件操作了
就是这个传过来的目录文件不能正确收到。我试验的这个文件大概只有几百K左右。
//文件接收不到?你的东东太长了,你先写个只传文件的测试一下,(你所有东西都传来了,你做软件还是我做软件啊?:)要注意版权啊)
没有帮你解决问题,我不要分了:)
 
太长了,真的没耐心看完,等我有心情的时候吧!
当然可能回连接在一起!采用多次握手的方法!
 
没有耐心看了,帮你顶一下。
 
天啦,不要没有耐心啊,要抱着科学严谨的态度啊
要是写的短一点也可以,我只是怕我说的问题你们不清楚
所以我把最详细的都写出来了
我甚至不在乎什么版权,只要能做出来,你们谁都可以拿去用
只要你们觉得的用的上,我绝不计较
我现在的问题就是:帮帮我吧,让它正常运行起来,如果长,你们不关心的地方可以省略。
 
发给我代码。我试试给你调一下。
我最近正在研究indy的使用。感觉还可以。】
SUIButton, StdCtrls, SUIEdit, DBXpress, DB, SqlExpr,
IdBaseComponent, IdComponent, IdTCPServer
你难道用了suipack,dbexpress,indy.用的控件也够多的。还好我都装了。呵呵!
indy的demo不知你看了没。ftp的demo很清楚。
你可以先发一个cmd的指令或是密码什么的。让对方确认就可以了。
 
数据合在一起很正常的,Delphi是以数据包来分割字符串的,即使你的服务器端没有紧接着发数据,也有可能会在客户端一起接收到,因为在客户端他们是紧接着到达的
如果要分割密码验证信息和文件内容,可以用标志字符串或者发送数据长度来分割
 
To : wang_phoenix
留下你的Email,我发给你源码。
 
intraweb@tom.com
 
To:wang_phoenix,
  你有没有发给我啊?我一直没有收到啊
 
这种代码在这看不出什么来的
 
楼上,如果你需要我的源码去试,我也以可以发给你
我的QQ:18832809
我的MSN:yourkeychen@hotmail.com
 
用包的方式可以很好的解决粘包问题,原理如下:

定一个包头,包括以下信息:

type
 // 定义包头(所有数据包共有的部分)
THEADER=packed record
  CommandID :LongWord;  // 命令,用以区分不同的包
Length :LongWord; // 包长度(包头+包体)
end;

// 定义包体
TBODY1=packed record
Name :array[0..10] of char;
content:array[0..1023] of char;
....
end;

.......


用SendBuf发送完整的数据包(包头+包体),在接收端先接收包头,得到整个数据包的长度,再接收包体,如此循环就可以就将粘包分开

recilen:=socket.ReceiveLength;
while recilen<0 do begin
读包头
  case 包头.CommandID of
读相应的包体
end
recilen=recilen-包体长度
end;
 
呵呵,电话都打了那么常事件,你搞定了可要给分咯
 
顶部