用B/S吧,再不是就用D6的新特点web方面的
解决方案 »
- 如何将程序分为界面exe和逻辑控制dll的形势,非数据库编程
- delphi多继承实现问题
- 这个distinct语句怎么写?
- 在网上自动安装 CAB 图标是在 DELPHI 那里修改的
- 提问:windows下用Midas编写的三层系统在Kylix中有何替代方案 ?
- 我自己建的QQ群,欢迎加入
- 关于流的问题:怎么处理流到DataSet中去,存进去又如何读入到OleContainer中去,多谢帮忙!
- borland公司有没有开发WINCE程序的环境啊?
- 有两台电脑,一台电脑输入后要在另一台上显示出来,怎么处理。
- 40分求救,高手救命!!!!
- 100分,请各位朋友帮忙,adotable这个mastersource和masterfields属性挡住我了??
- 广东有哪些公司名声很差
客户端和服务器发送命令,服务器收到后向客户端传送数据。
具体怎么做,没时间。
《深入delphi6网络编程》有讲socket编程。
我用的ics,帮助太少了
我和其他人一起,曾用WinSocket编写过一个‘网上考试系统’,里面允许客户端(如参加考试的考生或提供考题的教师等)可以通过internet来存取服务器端的数据。程序总的工作量不少于1.5个人年。我可以把我们的程序中和您有关的一部门告诉您。但为此需要去查看原来的源程序,让我今晚来做这一工作,也要把文字组织一下,争取在明天能在这里出帖子。
经过对我原来的‘网上考试系统’的查看,整理后,现归纳如下:
要了解用socket实现远程数据库访问,可分为以下几步进行:
1。了解访问数据库前,应做的连接工作。
2。了解客户机把数据存入服务器的数据库的过程。这又可分解为3个过程:
(1)客户机怎样向服务器发数据
(2)服务器怎样接收客户机发送来的数据
(3)服务器怎样把接收到的数据放入数据库
3。了解客户机从服务器的数据库读取数据的过程。这可分解为4个子过程:
(1)客户机怎样向服务器发索取数据的请求
(2)服务器怎样从相应数据库取出数据
(3)服务器怎样把数据送给客户机
(4)客户机怎样接收服务器发来的数据
4。了解访问数据库后,应做的断开连接工作。下面结合我的经验来说明各个步骤的实现,仅供您参考。1。访问数据库前应做的准备工作。
* 服务器应开机并运行通信软件,使其处在监听状态。为此,此软件
应使用delphi的InterNet页上的ServerSocket组件,
并设置ServerSocket的属性:
. name=serverSocket;
. port=1100;
. ServerType=stNonBlocking;
. active:=true; // 激活它
* 客户机使用InterNet页上的ClientSocket组件,并设置
ClientSocket的属性:
. name=ClientSocket;
. address=服务器IP地址,
. port=服务器port号,即1100;
. ServerType=stNonBlocking;
. active=true; // 激活它
* 完成双方以上的设置后,通信所需连接就完成
[注]这些工作也可在运行时完成,特别是为ClientSocket选取服务器
IP地址和port号。但我们在考试系统中则完全固定。
2.(1)客户机向服务器发数据,利用:
ClientSocket.Socket.SendText(SendText);
SendText在我们的系统中代表考生的姓名、身份证号,也可以是
考完后提交的考卷答案。
当SendText到达服务器1100端口,会引起ServerSocket的
ServerSocketClientRead()事件发生。所以
2.(2)服务器接收客户机发送来的数据可利用以下过程来实现:
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
RT:=Socket.ReceiveText; //RT就是考生姓名,身份证号,或答案
... //这里就是将RT放入数据库的操作,详见下一步
end;
2.(3)服务器把接收到的数据RT放入数据库:
这就是将RT插入某数据表(如tableK)的某个field(如fields[M]),故可用
tableK.fields[M].asstring:=RT或RT的一部分
来完成。但由于我们上面是用同一过程来接收所有的信息,所以必须首先
区别出收到的RT是什么信息,为此,学生用的考试软件在发送每一文本时,
其前面都带有标识符,如姓名前加'XM=',身份证号前加'ID=',考卷答案前
加'DA=';根据标识符就可判定信息的类型,并由此来确定应存入的table
名及field号。存入前,则应将RT前面的标识符去掉,再进行保存。[第3点待续]
其实就是要自己定义一套传输协议,比如哪些字符串
是代表用户名,哪些字符串代表密码,哪些代表删除
操作, 哪些代表添加操作,等等.
hard hard study,
day day up!
3.(1)客户机向服务器发索取数据的请求
这一步在考试进行时考生所用模块中实际不存在,因为系统知道来登录的
人(考生)所要的数据就是考试题目,不会有别的。且服务器在考试进行时
向考生软件发送的东西(除了考卷,还包括登录应答信息以及考生照片,
后者供监考人对考生验名正身)都按步骤自动完成,不允许对话选择。但
作为一般服务器,客户机应能向它索取不同数据表的不同域的数据。例如,
考生查询考试成绩的模块就应允许考生查询它的不同课目的考试成绩。为
此,可类似前面讲的采用不同标识的办法来实现,如用‘CXSJ=?’来查程
序设计的成绩,用‘WYSJ=?’来查程网页设计的成绩,等等。
3.(2)服务器从相应数据库取出数据
设各课成绩都在table3中(也可为此表起个易于记忆的名称如TbScores)
而程序设计放在此表的第4个域,则
cxsj:=table3.fields[4].asstring;
就实现了从成绩表中提取了程序设计的成绩, CXSJ是一字符串。
3.(3)服务器把数据送给客户机
Socket.sendtext(CXSJ);
服务器利用SendText把CXSJ发送到客户机,会引起它的ClientSocket的
ClientSocketRead()事件发生。所以
3.(4)客户机接收服务器发来的数据,可用以下过程来实现:
procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
RT:=Socket.ReceiveText; //RT就是考生查询得到的成绩字符串
... //这里通常是将RT用某种方式显示出来
end;4。访问数据库后,断开连接。
通信的任何一方若将其对应的Socket的Active属性设置为False,都
将使已建立的连接断开。而连接一断开,又会使双方都发生一个叫做
OnDisconnect()的连接断开事件。OnDisconnect()事件中要做的工作
通常是释放内存。以上讲的过程只是一个扼要,有不少东西都未仔细地讲清,还有其它问题没有讲,所以是不全面的,需要参考更多的资料才行。我觉得,首先可看的是delphi自带的一个聊天(chat)程序,它在delphi\demo\internet\chat的子目录中。
如果各位觉得有用可以“收藏”呀!
根据《Delphi 5编程实例与技巧》的第15章的例程
生成server.exe和client.exe,在打开server端后
再执行client.exe,输入服务器端的IP address,确定出错
“windons socket error: (10049),on API 'connect'”
----------------------------------------------------
client端代码如下:
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, Menus, StdCtrls, ComCtrls;type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
MainMenu1: TMainMenu;
action1: TMenuItem;
connect1: TMenuItem;
quit1: TMenuItem;
disconnect1: TMenuItem;
ClientSocket1: TClientSocket;
StatusBar1: TStatusBar;
procedure connect1Click(Sender: TObject);
procedure Memo1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure disconnect1Click(Sender: TObject);
procedure quit1Click(Sender: TObject);
procedure ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
addr:string;
implementation{$R *.DFM}procedure TForm1.connect1Click(Sender: TObject);begin
if clientsocket1.Active then clientsocket1.Active:=false;
if inputquery('connect to computer','IP address',addr) then
begin
with clientsocket1 do
begin
address:=addr;
active:=true;//出错??
StatusBar1.Panels[0].Text:='connecting to'+addr+'...';
end;
end
end;procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key=VK_Return then
clientsocket1.Socket.SendText(memo1.lines[memo1.lines.count-1]);
end;procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
begin
memo2.Lines.add(socket.ReceiveText);
end;procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
statusbar1.Panels[0].Text:='connected to'+addr;
end;procedure TForm1.disconnect1Click(Sender: TObject);
begin
clientsocket1.Active:=false;
statusbar1.Panels[0].Text:='';
end;procedure TForm1.quit1Click(Sender: TObject);
begin
clientsocket1.Active:=false;
close;
end;procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
statusbar1.Panels[0].Text:=Socket.RemoteAddress+'disconnect';
end;end.server端代码如下:
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus, StdCtrls, ScktComp, ComCtrls;type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
Memo1: TMemo;
Memo2: TMemo;
MainMenu1: TMainMenu;
socket1: TMenuItem;
listen1: TMenuItem;
quit1: TMenuItem;
StatusBar1: TStatusBar;
procedure listen1Click(Sender: TObject);
procedure ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure Memo1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure quit1Click(Sender: TObject);
private
{ Private declarations }
public
procedure sendtoclient(text:string);
end;var
Form1: TForm1;implementation{$R *.DFM}
procedure TForm1.sendtoclient(text:string);
var i:integer;
begin
for i:=0 to serversocket1.Socket.ActiveConnections-1 do
serversocket1.Socket.Connections[i].SendText(text);
end;procedure TForm1.listen1Click(Sender: TObject);
begin
(sender as Tmenuitem).checked:=not(sender as Tmenuitem).checked;
if (sender as Tmenuitem).checked then
begin
ServerSocket1.Active:=true;
StatusBar1.Panels[0].Text:='listen on port['+inttostr(ServerSocket1.Port)+']...';
end
else
begin
ServerSocket1.Active:=false;
StatusBar1.Panels[0].Text:='';
end;
end;procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.Panels[0].Text:='connected by'+Socket.RemoteAddress;
end;procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.Panels[0].Text:=Socket.RemoteAddress+'disconnected';
end;procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
memo2.lines.add(Socket.ReceiveText);
end;procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key=VK_Return then
begin
sendtoclient(memo1.Lines[memo1.Lines.Count-1]);
end;
end;procedure TForm1.quit1Click(Sender: TObject);
begin
sendtoclient('bye-bye');//退出时对各个客户端说再见
if serversocket1.Active then
serversocket1.Active:=false;
close;
end;end.
不能为0,指定为其它相同值即可!
很高兴呀,谢谢zzwu(未名) 高手指点,
各位还有高见请发表。分数不够再开,只要是互相学习...
不过那些只是具体实现上的问题,都可以解决,服务端,你使用的是非阻塞方式,它是在主线程中处理通讯的,
也就是说,不管多少客户端连接过来,你能只能在GUI线程中
处理数据库,这样效率并不高.还有,当网络稍忙时,多个客户端的几个Send操作,只能触发一次
服务端的OnRead事件,下面这样在具体处理上要修改. procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
RT:=Socket.ReceiveText; //RT就是考生姓名,身份证号,或答案
... //这里就是将RT放入数据库的操作,详见下一步 end;
建议: 编写描述协议这样的文档,而不是具体实现上.
1.如果说客户端只是向总部填写数据,查询信息,我想用Stringgrid表示记录的格式更好。以1条记录以上为传送前提(不是以字段),当然要有好的解释程序(server端对发来的客户端数据解释后写入server数据库,当然客户端也有类似的解释程序,查询时用)2.如果说客户端是独立的系统有本地数据库如access表可以用DBGrid等数据敏感控件了,该段程序只是起了交换数据的作用。当然要有好的解释程序。
-------------------------
你们提出的做法都很有道理;
我们的系统在实际做时,也和我上面的描述不完全相同.同时,还有不少十分重要的事情前面没有讲.所以,今后还需要(如果zhangpeigao自己也感到需要的话)进一步讨论.
不要这么费事。