是阻塞方式的一个简单聊天程序。只能发送Edit里面的字符串。
用一个线程来控制其监听状态。
客户端或服务端程序结束了,只要对方没关,就还会不断地向对方发送重复的消息。
这是什么回事?
Up的人,有分
解决的人 另外再加100
22 个解决方案
#1
不懂,up
#2
up
#3
就是一方(Client.exe)退出程序后,竟然还能死循环的向另一方(Server.exe)
发送信息。这是怎么回事呢??
发送信息。这是怎么回事呢??
#4
呵呵~人家还没聊完你就关了,对你表示不满嘛~
不过不应该出现啊~估计不难,但是我没有这方面经验~
不过不应该出现啊~估计不难,但是我没有这方面经验~
#5
是源源不断地发送消息,还是在退出之前在发送一次。建议看看socket的各个事件代码。
#6
是源源不断地发送消息
#7
而且我已经退出前把线程Teminel掉了阿。
会是什么原因阿?
会是什么原因阿?
#8
我方的程序都退出了,关闭了,还怎么向对方发送消息?不明白!
如果是我不知道对方的程序已经关掉了,还源源不断地向对方发送消息,那就是你的通信协议的问题,如果是用有应答的发送消息协议,一旦连接出了问题(一方断掉后),数据将发送不成功!TSocketServer/TSocketClient有此功能。
如果不能解决,请贴出代码,帮你想一下吧.
如果是我不知道对方的程序已经关掉了,还源源不断地向对方发送消息,那就是你的通信协议的问题,如果是用有应答的发送消息协议,一旦连接出了问题(一方断掉后),数据将发送不成功!TSocketServer/TSocketClient有此功能。
如果不能解决,请贴出代码,帮你想一下吧.
#9
客户端的代码:
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,WinSock;
type
TSyncThread=class(TThread)
protected
procedure execute;override;
private
procedure RecvText;
end;
type
TMainFrame = class(TForm)
EditServerIP: TEdit;
EditServerPort: TEdit;
LbPort: TLabel;
LbIP: TLabel;
BtnConnect: TButton;
StatusBarClient: TStatusBar;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSend: TButton;
BtnExit: TButton;
procedure BtnExitClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnConnectClick(Sender: TObject);
procedure BtnSendClick(Sender: TObject);
procedure EditMsgKeyPress(Sender: TObject; var Key: Char);
private
ThreadClient:TSyncThread;
{ Private declarations }
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ClientSocket:TSocket;
BlockBuf:array [0..1024*4-1] of char;
RecvBuf:array[0..1024*4-1] of char;
const BufLength=1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
begin
while (true) do
begin
recv(ClientSocket,RecvBuf,BufLength,0);
Synchronize(RecvText);
MainFrame.Update;
end;
end;
procedure TSyncThread.RecvText;
begin
MainFrame.ListBoxUsers.Items.Add('Server');
MainFrame.ListBoxMsg.Items.Add(RecvBuf);
end;
procedure TMainFrame.BtnExitClick(Sender: TObject);
begin
ThreadClient.Terminate;
Close;
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var aWSAData:TWSAData;
begin
if WSAStartup($0101,aWSAData)<>0 then
begin
raise Exception.Create('Could not start up the Socket Dll');
end;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if WSACleanup<>0 then
begin
MessageBox(Handle,'Can not clean up the Winsock dll','Error Msg',MB_OK);
end;
CloseSocket(ClientSocket);
end;
procedure TMainFrame.BtnConnectClick(Sender: TObject);
var
ca: SOCKADDR_IN;
hostaddr:u_long;
begin
ClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ClientSocket=INVALID_SOCKET then
begin
StatusBarClient.SimpleText:='Can not Connect to a Server';
exit;
end;
ca.sin_family:=PF_INET;
ca.sin_port:=htons(StrToInt(Trim(EditServerPort.Text)));
hostaddr:=inet_addr(PChar(Trim(EditServerIP.Text)));
if(hostaddr=-1) then
begin
statusBarClient.SimpleText:='The ip Addr is wrong ';
exit;
end
else
ca.sin_addr.S_addr:=hostaddr;
if connect(ClientSocket,ca,sizeof(ca))<>0 then
begin
StatusBarClient.SimpleText:='Can not Connect to romete host';
exit;
end
else
begin
StatusBarClient.SimpleText:='Connect to remote host succeed';
ThreadClient:=TSyncThread.Create(false);
BtnConnect.Enabled:=false;
end;
end;
procedure TMainFrame.BtnSendClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(ClientSocket,BlockBuf,BufLength,0);
MainFrame.ListBoxUsers.Items.Add('me');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.EditMsgKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
BtnSendClick(Sender);
end;
end.
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,WinSock;
type
TSyncThread=class(TThread)
protected
procedure execute;override;
private
procedure RecvText;
end;
type
TMainFrame = class(TForm)
EditServerIP: TEdit;
EditServerPort: TEdit;
LbPort: TLabel;
LbIP: TLabel;
BtnConnect: TButton;
StatusBarClient: TStatusBar;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSend: TButton;
BtnExit: TButton;
procedure BtnExitClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnConnectClick(Sender: TObject);
procedure BtnSendClick(Sender: TObject);
procedure EditMsgKeyPress(Sender: TObject; var Key: Char);
private
ThreadClient:TSyncThread;
{ Private declarations }
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ClientSocket:TSocket;
BlockBuf:array [0..1024*4-1] of char;
RecvBuf:array[0..1024*4-1] of char;
const BufLength=1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
begin
while (true) do
begin
recv(ClientSocket,RecvBuf,BufLength,0);
Synchronize(RecvText);
MainFrame.Update;
end;
end;
procedure TSyncThread.RecvText;
begin
MainFrame.ListBoxUsers.Items.Add('Server');
MainFrame.ListBoxMsg.Items.Add(RecvBuf);
end;
procedure TMainFrame.BtnExitClick(Sender: TObject);
begin
ThreadClient.Terminate;
Close;
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var aWSAData:TWSAData;
begin
if WSAStartup($0101,aWSAData)<>0 then
begin
raise Exception.Create('Could not start up the Socket Dll');
end;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if WSACleanup<>0 then
begin
MessageBox(Handle,'Can not clean up the Winsock dll','Error Msg',MB_OK);
end;
CloseSocket(ClientSocket);
end;
procedure TMainFrame.BtnConnectClick(Sender: TObject);
var
ca: SOCKADDR_IN;
hostaddr:u_long;
begin
ClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ClientSocket=INVALID_SOCKET then
begin
StatusBarClient.SimpleText:='Can not Connect to a Server';
exit;
end;
ca.sin_family:=PF_INET;
ca.sin_port:=htons(StrToInt(Trim(EditServerPort.Text)));
hostaddr:=inet_addr(PChar(Trim(EditServerIP.Text)));
if(hostaddr=-1) then
begin
statusBarClient.SimpleText:='The ip Addr is wrong ';
exit;
end
else
ca.sin_addr.S_addr:=hostaddr;
if connect(ClientSocket,ca,sizeof(ca))<>0 then
begin
StatusBarClient.SimpleText:='Can not Connect to romete host';
exit;
end
else
begin
StatusBarClient.SimpleText:='Connect to remote host succeed';
ThreadClient:=TSyncThread.Create(false);
BtnConnect.Enabled:=false;
end;
end;
procedure TMainFrame.BtnSendClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(ClientSocket,BlockBuf,BufLength,0);
MainFrame.ListBoxUsers.Items.Add('me');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.EditMsgKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
BtnSendClick(Sender);
end;
end.
#10
服务端的代码
unit Server;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,Winsock;
type
TSyncThread =class(TThread)
protected
procedure execute ; override;
public
procedure AddRecvMsg;
end;
TMainFrame = class(TForm)
BtnStartServer: TButton;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
BtnExitServer: TButton;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSendMsg: TButton;
StatusBarServer: TStatusBar;
procedure BtnStartServerClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtnExitServerClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnSendMsgClick(Sender: TObject);
procedure EditMsgEnter(Sender: TObject);
private
{ Private declarations }
ThreadListen:TSyncThread;
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ServerSocket :TSocket;
RecvSocket :TSocket;
BlockBuf:Array [0..1024*4-1] of char;
const BufLength =1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
var
ra:SOCKADDR_IN;
ra_len:Integer;
begin
ra_len:=sizeof(ra);
RecvSocket:=accept(ServerSocket,@ra,@ra_len);
while (true) do
begin
recv(RecvSocket,BlockBuf,BufLength,0);
Synchronize(AddRecvMsg);
MainFrame.Update;
end;
;
end;
procedure TSyncThread.AddRecvMsg;
begin
MainFrame.ListBoxUsers.Items.Add('Client');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.BtnStartServerClick(Sender: TObject);
var
ca:SOCKADDR_IN;
begin
ServerSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ServerSocket=INVALID_SOCKET then
begin
StatusBarServer.SimpleText:='Creating Accept Socket Server Error';
Exit;
end
else
ca.sin_family:=PF_INET;
ca.sin_port:=htons(3000);
ca.sin_addr.S_addr:=INADDR_ANY;
if Bind(ServerSocket,ca,sizeof(ca))=SOCKET_ERROR then
begin
StatusBarServer.SimpleText:='Binding the Server Socket Error';
CloseSocket(ServerSocket);
exit;
end
else
StatusBarServer.SimpleText:='Binding the Server Socket Succeed!';
try
listen(ServerSocket,5);
except
on e:Exception do
showmessage(e.Message);
end;
BtnStartServer.Enabled:=false;
ThreadListen:=TsyncThread.Create(false);
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var
aWSAData:TWSADATA;
begin
if WSAStartup($0101,aWSAData)<>0 then
raise Exception.Create('Can not load the Socket Dll#13');
end;
procedure TMainFrame.BtnExitServerClick(Sender: TObject);
begin
Close;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
MessageBox(Handle,'Clean the Winsock dll wrong','Error Messge',MB_OK);
end;
procedure TMainFrame.BtnSendMsgClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(RecvSocket,BlockBuf,BufLength,0);
ListBoxMsg.Items.Add(BlockBuf);
ListBoxUsers.Items.Add('Me');
end;
procedure TMainFrame.EditMsgEnter(Sender: TObject);
begin
BtnSendMsgClick(Sender);
end;
end.
unit Server;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,Winsock;
type
TSyncThread =class(TThread)
protected
procedure execute ; override;
public
procedure AddRecvMsg;
end;
TMainFrame = class(TForm)
BtnStartServer: TButton;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
BtnExitServer: TButton;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSendMsg: TButton;
StatusBarServer: TStatusBar;
procedure BtnStartServerClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtnExitServerClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnSendMsgClick(Sender: TObject);
procedure EditMsgEnter(Sender: TObject);
private
{ Private declarations }
ThreadListen:TSyncThread;
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ServerSocket :TSocket;
RecvSocket :TSocket;
BlockBuf:Array [0..1024*4-1] of char;
const BufLength =1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
var
ra:SOCKADDR_IN;
ra_len:Integer;
begin
ra_len:=sizeof(ra);
RecvSocket:=accept(ServerSocket,@ra,@ra_len);
while (true) do
begin
recv(RecvSocket,BlockBuf,BufLength,0);
Synchronize(AddRecvMsg);
MainFrame.Update;
end;
;
end;
procedure TSyncThread.AddRecvMsg;
begin
MainFrame.ListBoxUsers.Items.Add('Client');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.BtnStartServerClick(Sender: TObject);
var
ca:SOCKADDR_IN;
begin
ServerSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ServerSocket=INVALID_SOCKET then
begin
StatusBarServer.SimpleText:='Creating Accept Socket Server Error';
Exit;
end
else
ca.sin_family:=PF_INET;
ca.sin_port:=htons(3000);
ca.sin_addr.S_addr:=INADDR_ANY;
if Bind(ServerSocket,ca,sizeof(ca))=SOCKET_ERROR then
begin
StatusBarServer.SimpleText:='Binding the Server Socket Error';
CloseSocket(ServerSocket);
exit;
end
else
StatusBarServer.SimpleText:='Binding the Server Socket Succeed!';
try
listen(ServerSocket,5);
except
on e:Exception do
showmessage(e.Message);
end;
BtnStartServer.Enabled:=false;
ThreadListen:=TsyncThread.Create(false);
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var
aWSAData:TWSADATA;
begin
if WSAStartup($0101,aWSAData)<>0 then
raise Exception.Create('Can not load the Socket Dll#13');
end;
procedure TMainFrame.BtnExitServerClick(Sender: TObject);
begin
Close;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
MessageBox(Handle,'Clean the Winsock dll wrong','Error Messge',MB_OK);
end;
procedure TMainFrame.BtnSendMsgClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(RecvSocket,BlockBuf,BufLength,0);
ListBoxMsg.Items.Add(BlockBuf);
ListBoxUsers.Items.Add('Me');
end;
procedure TMainFrame.EditMsgEnter(Sender: TObject);
begin
BtnSendMsgClick(Sender);
end;
end.
#11
帮忙看看谢谢
#12
分析你的代码,是不会出现那种情况的
打开两份Delphi 一份运行客户端,一份运行服务端,同时打开线程监视器,单步运行程序,进入线程查看信息。
打开两份Delphi 一份运行客户端,一份运行服务端,同时打开线程监视器,单步运行程序,进入线程查看信息。
#13
我也遇到过这个问题, 我是用andy组件时发现的。服务器端向客户端连续发送数据,客户端收到后就显示出来。后来我发现关了服务端后客户端仍然能显示数据。之后我在客户端检测与服务端的连接状态,当服务端关闭后,客户端能检测到,但仍然能从指定的端口读取数据。这个问题我还没解决,只当客户端检测到服务端已关闭时就不再去读取数据了。
#14
我理解如下:
你的服务端程序没有保存客户端连接信息,当客户端退出后,在服务端没有表示,这样服务端程序将源源不断地向不存在的客户端发送信息,但这也会带来很多问题,你用的是“阻塞方式”
强烈建议你用两份Delphi同时单步调试客户端和服务端程序,仔细一点,问题是应该可以解决的
你的服务端程序没有保存客户端连接信息,当客户端退出后,在服务端没有表示,这样服务端程序将源源不断地向不存在的客户端发送信息,但这也会带来很多问题,你用的是“阻塞方式”
强烈建议你用两份Delphi同时单步调试客户端和服务端程序,仔细一点,问题是应该可以解决的
#15
是不是要在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室...
如此一来客户端的连接状态,(当前有多少个用户,在多少人只听不说...),怎么处理?
如此一来客户端的连接状态,(当前有多少个用户,在多少人只听不说...),怎么处理?
#16
HanJingJingHan(静) :谢谢你的分析,我才刚学delphi。可能你说得对
服务端程序没有保存客户端连接信息。但是客户端退出的时候,从服务端
Disconect掉了吧。
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
如果这样还不能清除信息,那怎么做才对呢?谢谢
服务端程序没有保存客户端连接信息。但是客户端退出的时候,从服务端
Disconect掉了吧。
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
如果这样还不能清除信息,那怎么做才对呢?谢谢
#17
我发现很有趣。打开一个server.exe.
2个Client.exe.
结果很怪的。 有时服务端收不到信息。
Client(1).exe 的信息不能发到 Client(2).exe
"
在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室..."
恐怕是这个原因,怎么解决呢?
2个Client.exe.
结果很怪的。 有时服务端收不到信息。
Client(1).exe 的信息不能发到 Client(2).exe
"
在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室..."
恐怕是这个原因,怎么解决呢?
#18
试一下Delphi自带的两个组件,TSocoktServer/TSocoktClient,你所需要的绝大部分功能它都替你做好了,而它的功能也足够地强大,我公司的整个短信网关系统,后台处理系统都是用它做的,你可以读一下它的源码。另外如果你是用D5版本的话,它的Demo文件夹下有一个专门的文件夹我,有好多关于通信编程的源码,非常的实用。
#19
还有许多关于用Delphi进行网络编程的书籍上都有用Delphi写聊天室的源码和思想,注意事项。
如果你只是偶尔写一点就不必那么费力了,如果你想深入地用Delphi进行网络编程,建议你到书店去找一找,依葫芦化瓢,不出10天就会了,如果深入一些,将无量...
如果你只是偶尔写一点就不必那么费力了,如果你想深入地用Delphi进行网络编程,建议你到书店去找一找,依葫芦化瓢,不出10天就会了,如果深入一些,将无量...
#20
嗯,谢谢,可是这样不好阿,遇到问题解决不了,总是有点嘎达嘎大的感觉。。
哎。。
哎。。
#21
如果是程序的某一个地方出问题,改动量小的话,就立马可以解决,问题是当一个问题头绪多乱或者不是三言两语能说清楚的话,就只能靠自己去学习了,旁人只能指个路。
相比之下,有个人指个方向,学习的进度就大不一样了。
相比之下,有个人指个方向,学习的进度就大不一样了。
#22
哎,那倒是,哦,你有油箱嘛?要不我发完整程序给你看看吧?谢谢。
#1
不懂,up
#2
up
#3
就是一方(Client.exe)退出程序后,竟然还能死循环的向另一方(Server.exe)
发送信息。这是怎么回事呢??
发送信息。这是怎么回事呢??
#4
呵呵~人家还没聊完你就关了,对你表示不满嘛~
不过不应该出现啊~估计不难,但是我没有这方面经验~
不过不应该出现啊~估计不难,但是我没有这方面经验~
#5
是源源不断地发送消息,还是在退出之前在发送一次。建议看看socket的各个事件代码。
#6
是源源不断地发送消息
#7
而且我已经退出前把线程Teminel掉了阿。
会是什么原因阿?
会是什么原因阿?
#8
我方的程序都退出了,关闭了,还怎么向对方发送消息?不明白!
如果是我不知道对方的程序已经关掉了,还源源不断地向对方发送消息,那就是你的通信协议的问题,如果是用有应答的发送消息协议,一旦连接出了问题(一方断掉后),数据将发送不成功!TSocketServer/TSocketClient有此功能。
如果不能解决,请贴出代码,帮你想一下吧.
如果是我不知道对方的程序已经关掉了,还源源不断地向对方发送消息,那就是你的通信协议的问题,如果是用有应答的发送消息协议,一旦连接出了问题(一方断掉后),数据将发送不成功!TSocketServer/TSocketClient有此功能。
如果不能解决,请贴出代码,帮你想一下吧.
#9
客户端的代码:
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,WinSock;
type
TSyncThread=class(TThread)
protected
procedure execute;override;
private
procedure RecvText;
end;
type
TMainFrame = class(TForm)
EditServerIP: TEdit;
EditServerPort: TEdit;
LbPort: TLabel;
LbIP: TLabel;
BtnConnect: TButton;
StatusBarClient: TStatusBar;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSend: TButton;
BtnExit: TButton;
procedure BtnExitClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnConnectClick(Sender: TObject);
procedure BtnSendClick(Sender: TObject);
procedure EditMsgKeyPress(Sender: TObject; var Key: Char);
private
ThreadClient:TSyncThread;
{ Private declarations }
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ClientSocket:TSocket;
BlockBuf:array [0..1024*4-1] of char;
RecvBuf:array[0..1024*4-1] of char;
const BufLength=1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
begin
while (true) do
begin
recv(ClientSocket,RecvBuf,BufLength,0);
Synchronize(RecvText);
MainFrame.Update;
end;
end;
procedure TSyncThread.RecvText;
begin
MainFrame.ListBoxUsers.Items.Add('Server');
MainFrame.ListBoxMsg.Items.Add(RecvBuf);
end;
procedure TMainFrame.BtnExitClick(Sender: TObject);
begin
ThreadClient.Terminate;
Close;
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var aWSAData:TWSAData;
begin
if WSAStartup($0101,aWSAData)<>0 then
begin
raise Exception.Create('Could not start up the Socket Dll');
end;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if WSACleanup<>0 then
begin
MessageBox(Handle,'Can not clean up the Winsock dll','Error Msg',MB_OK);
end;
CloseSocket(ClientSocket);
end;
procedure TMainFrame.BtnConnectClick(Sender: TObject);
var
ca: SOCKADDR_IN;
hostaddr:u_long;
begin
ClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ClientSocket=INVALID_SOCKET then
begin
StatusBarClient.SimpleText:='Can not Connect to a Server';
exit;
end;
ca.sin_family:=PF_INET;
ca.sin_port:=htons(StrToInt(Trim(EditServerPort.Text)));
hostaddr:=inet_addr(PChar(Trim(EditServerIP.Text)));
if(hostaddr=-1) then
begin
statusBarClient.SimpleText:='The ip Addr is wrong ';
exit;
end
else
ca.sin_addr.S_addr:=hostaddr;
if connect(ClientSocket,ca,sizeof(ca))<>0 then
begin
StatusBarClient.SimpleText:='Can not Connect to romete host';
exit;
end
else
begin
StatusBarClient.SimpleText:='Connect to remote host succeed';
ThreadClient:=TSyncThread.Create(false);
BtnConnect.Enabled:=false;
end;
end;
procedure TMainFrame.BtnSendClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(ClientSocket,BlockBuf,BufLength,0);
MainFrame.ListBoxUsers.Items.Add('me');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.EditMsgKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
BtnSendClick(Sender);
end;
end.
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,WinSock;
type
TSyncThread=class(TThread)
protected
procedure execute;override;
private
procedure RecvText;
end;
type
TMainFrame = class(TForm)
EditServerIP: TEdit;
EditServerPort: TEdit;
LbPort: TLabel;
LbIP: TLabel;
BtnConnect: TButton;
StatusBarClient: TStatusBar;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSend: TButton;
BtnExit: TButton;
procedure BtnExitClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnConnectClick(Sender: TObject);
procedure BtnSendClick(Sender: TObject);
procedure EditMsgKeyPress(Sender: TObject; var Key: Char);
private
ThreadClient:TSyncThread;
{ Private declarations }
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ClientSocket:TSocket;
BlockBuf:array [0..1024*4-1] of char;
RecvBuf:array[0..1024*4-1] of char;
const BufLength=1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
begin
while (true) do
begin
recv(ClientSocket,RecvBuf,BufLength,0);
Synchronize(RecvText);
MainFrame.Update;
end;
end;
procedure TSyncThread.RecvText;
begin
MainFrame.ListBoxUsers.Items.Add('Server');
MainFrame.ListBoxMsg.Items.Add(RecvBuf);
end;
procedure TMainFrame.BtnExitClick(Sender: TObject);
begin
ThreadClient.Terminate;
Close;
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var aWSAData:TWSAData;
begin
if WSAStartup($0101,aWSAData)<>0 then
begin
raise Exception.Create('Could not start up the Socket Dll');
end;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if WSACleanup<>0 then
begin
MessageBox(Handle,'Can not clean up the Winsock dll','Error Msg',MB_OK);
end;
CloseSocket(ClientSocket);
end;
procedure TMainFrame.BtnConnectClick(Sender: TObject);
var
ca: SOCKADDR_IN;
hostaddr:u_long;
begin
ClientSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ClientSocket=INVALID_SOCKET then
begin
StatusBarClient.SimpleText:='Can not Connect to a Server';
exit;
end;
ca.sin_family:=PF_INET;
ca.sin_port:=htons(StrToInt(Trim(EditServerPort.Text)));
hostaddr:=inet_addr(PChar(Trim(EditServerIP.Text)));
if(hostaddr=-1) then
begin
statusBarClient.SimpleText:='The ip Addr is wrong ';
exit;
end
else
ca.sin_addr.S_addr:=hostaddr;
if connect(ClientSocket,ca,sizeof(ca))<>0 then
begin
StatusBarClient.SimpleText:='Can not Connect to romete host';
exit;
end
else
begin
StatusBarClient.SimpleText:='Connect to remote host succeed';
ThreadClient:=TSyncThread.Create(false);
BtnConnect.Enabled:=false;
end;
end;
procedure TMainFrame.BtnSendClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(ClientSocket,BlockBuf,BufLength,0);
MainFrame.ListBoxUsers.Items.Add('me');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.EditMsgKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
BtnSendClick(Sender);
end;
end.
#10
服务端的代码
unit Server;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,Winsock;
type
TSyncThread =class(TThread)
protected
procedure execute ; override;
public
procedure AddRecvMsg;
end;
TMainFrame = class(TForm)
BtnStartServer: TButton;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
BtnExitServer: TButton;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSendMsg: TButton;
StatusBarServer: TStatusBar;
procedure BtnStartServerClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtnExitServerClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnSendMsgClick(Sender: TObject);
procedure EditMsgEnter(Sender: TObject);
private
{ Private declarations }
ThreadListen:TSyncThread;
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ServerSocket :TSocket;
RecvSocket :TSocket;
BlockBuf:Array [0..1024*4-1] of char;
const BufLength =1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
var
ra:SOCKADDR_IN;
ra_len:Integer;
begin
ra_len:=sizeof(ra);
RecvSocket:=accept(ServerSocket,@ra,@ra_len);
while (true) do
begin
recv(RecvSocket,BlockBuf,BufLength,0);
Synchronize(AddRecvMsg);
MainFrame.Update;
end;
;
end;
procedure TSyncThread.AddRecvMsg;
begin
MainFrame.ListBoxUsers.Items.Add('Client');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.BtnStartServerClick(Sender: TObject);
var
ca:SOCKADDR_IN;
begin
ServerSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ServerSocket=INVALID_SOCKET then
begin
StatusBarServer.SimpleText:='Creating Accept Socket Server Error';
Exit;
end
else
ca.sin_family:=PF_INET;
ca.sin_port:=htons(3000);
ca.sin_addr.S_addr:=INADDR_ANY;
if Bind(ServerSocket,ca,sizeof(ca))=SOCKET_ERROR then
begin
StatusBarServer.SimpleText:='Binding the Server Socket Error';
CloseSocket(ServerSocket);
exit;
end
else
StatusBarServer.SimpleText:='Binding the Server Socket Succeed!';
try
listen(ServerSocket,5);
except
on e:Exception do
showmessage(e.Message);
end;
BtnStartServer.Enabled:=false;
ThreadListen:=TsyncThread.Create(false);
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var
aWSAData:TWSADATA;
begin
if WSAStartup($0101,aWSAData)<>0 then
raise Exception.Create('Can not load the Socket Dll#13');
end;
procedure TMainFrame.BtnExitServerClick(Sender: TObject);
begin
Close;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
MessageBox(Handle,'Clean the Winsock dll wrong','Error Messge',MB_OK);
end;
procedure TMainFrame.BtnSendMsgClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(RecvSocket,BlockBuf,BufLength,0);
ListBoxMsg.Items.Add(BlockBuf);
ListBoxUsers.Items.Add('Me');
end;
procedure TMainFrame.EditMsgEnter(Sender: TObject);
begin
BtnSendMsgClick(Sender);
end;
end.
unit Server;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,Winsock;
type
TSyncThread =class(TThread)
protected
procedure execute ; override;
public
procedure AddRecvMsg;
end;
TMainFrame = class(TForm)
BtnStartServer: TButton;
ListBoxUsers: TListBox;
ListBoxMsg: TListBox;
BtnExitServer: TButton;
LbMsg: TLabel;
EditMsg: TEdit;
BtnSendMsg: TButton;
StatusBarServer: TStatusBar;
procedure BtnStartServerClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtnExitServerClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnSendMsgClick(Sender: TObject);
procedure EditMsgEnter(Sender: TObject);
private
{ Private declarations }
ThreadListen:TSyncThread;
public
{ Public declarations }
end;
var
MainFrame: TMainFrame;
ServerSocket :TSocket;
RecvSocket :TSocket;
BlockBuf:Array [0..1024*4-1] of char;
const BufLength =1024*4;
implementation
{$R *.dfm}
procedure TSyncThread.execute;
var
ra:SOCKADDR_IN;
ra_len:Integer;
begin
ra_len:=sizeof(ra);
RecvSocket:=accept(ServerSocket,@ra,@ra_len);
while (true) do
begin
recv(RecvSocket,BlockBuf,BufLength,0);
Synchronize(AddRecvMsg);
MainFrame.Update;
end;
;
end;
procedure TSyncThread.AddRecvMsg;
begin
MainFrame.ListBoxUsers.Items.Add('Client');
MainFrame.ListBoxMsg.Items.Add(BlockBuf);
end;
procedure TMainFrame.BtnStartServerClick(Sender: TObject);
var
ca:SOCKADDR_IN;
begin
ServerSocket:=Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if ServerSocket=INVALID_SOCKET then
begin
StatusBarServer.SimpleText:='Creating Accept Socket Server Error';
Exit;
end
else
ca.sin_family:=PF_INET;
ca.sin_port:=htons(3000);
ca.sin_addr.S_addr:=INADDR_ANY;
if Bind(ServerSocket,ca,sizeof(ca))=SOCKET_ERROR then
begin
StatusBarServer.SimpleText:='Binding the Server Socket Error';
CloseSocket(ServerSocket);
exit;
end
else
StatusBarServer.SimpleText:='Binding the Server Socket Succeed!';
try
listen(ServerSocket,5);
except
on e:Exception do
showmessage(e.Message);
end;
BtnStartServer.Enabled:=false;
ThreadListen:=TsyncThread.Create(false);
end;
procedure TMainFrame.FormCreate(Sender: TObject);
var
aWSAData:TWSADATA;
begin
if WSAStartup($0101,aWSAData)<>0 then
raise Exception.Create('Can not load the Socket Dll#13');
end;
procedure TMainFrame.BtnExitServerClick(Sender: TObject);
begin
Close;
end;
procedure TMainFrame.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
MessageBox(Handle,'Clean the Winsock dll wrong','Error Messge',MB_OK);
end;
procedure TMainFrame.BtnSendMsgClick(Sender: TObject);
begin
strpcopy(BlockBuf,MainFrame.EditMsg.Text);
send(RecvSocket,BlockBuf,BufLength,0);
ListBoxMsg.Items.Add(BlockBuf);
ListBoxUsers.Items.Add('Me');
end;
procedure TMainFrame.EditMsgEnter(Sender: TObject);
begin
BtnSendMsgClick(Sender);
end;
end.
#11
帮忙看看谢谢
#12
分析你的代码,是不会出现那种情况的
打开两份Delphi 一份运行客户端,一份运行服务端,同时打开线程监视器,单步运行程序,进入线程查看信息。
打开两份Delphi 一份运行客户端,一份运行服务端,同时打开线程监视器,单步运行程序,进入线程查看信息。
#13
我也遇到过这个问题, 我是用andy组件时发现的。服务器端向客户端连续发送数据,客户端收到后就显示出来。后来我发现关了服务端后客户端仍然能显示数据。之后我在客户端检测与服务端的连接状态,当服务端关闭后,客户端能检测到,但仍然能从指定的端口读取数据。这个问题我还没解决,只当客户端检测到服务端已关闭时就不再去读取数据了。
#14
我理解如下:
你的服务端程序没有保存客户端连接信息,当客户端退出后,在服务端没有表示,这样服务端程序将源源不断地向不存在的客户端发送信息,但这也会带来很多问题,你用的是“阻塞方式”
强烈建议你用两份Delphi同时单步调试客户端和服务端程序,仔细一点,问题是应该可以解决的
你的服务端程序没有保存客户端连接信息,当客户端退出后,在服务端没有表示,这样服务端程序将源源不断地向不存在的客户端发送信息,但这也会带来很多问题,你用的是“阻塞方式”
强烈建议你用两份Delphi同时单步调试客户端和服务端程序,仔细一点,问题是应该可以解决的
#15
是不是要在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室...
如此一来客户端的连接状态,(当前有多少个用户,在多少人只听不说...),怎么处理?
如此一来客户端的连接状态,(当前有多少个用户,在多少人只听不说...),怎么处理?
#16
HanJingJingHan(静) :谢谢你的分析,我才刚学delphi。可能你说得对
服务端程序没有保存客户端连接信息。但是客户端退出的时候,从服务端
Disconect掉了吧。
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
如果这样还不能清除信息,那怎么做才对呢?谢谢
服务端程序没有保存客户端连接信息。但是客户端退出的时候,从服务端
Disconect掉了吧。
if ServerSocket<>INVALID_SOCKET then
closesocket(ServerSocket);
if WSACleanup<>0 then
如果这样还不能清除信息,那怎么做才对呢?谢谢
#17
我发现很有趣。打开一个server.exe.
2个Client.exe.
结果很怪的。 有时服务端收不到信息。
Client(1).exe 的信息不能发到 Client(2).exe
"
在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室..."
恐怕是这个原因,怎么解决呢?
2个Client.exe.
结果很怪的。 有时服务端收不到信息。
Client(1).exe 的信息不能发到 Client(2).exe
"
在服务端保存一下客户端的一些状态,单间地说,就是用户一的发言要发向所有人,用户二的发言只发向他的朋友,用户三进入聊天室,用户四退出聊天室..."
恐怕是这个原因,怎么解决呢?
#18
试一下Delphi自带的两个组件,TSocoktServer/TSocoktClient,你所需要的绝大部分功能它都替你做好了,而它的功能也足够地强大,我公司的整个短信网关系统,后台处理系统都是用它做的,你可以读一下它的源码。另外如果你是用D5版本的话,它的Demo文件夹下有一个专门的文件夹我,有好多关于通信编程的源码,非常的实用。
#19
还有许多关于用Delphi进行网络编程的书籍上都有用Delphi写聊天室的源码和思想,注意事项。
如果你只是偶尔写一点就不必那么费力了,如果你想深入地用Delphi进行网络编程,建议你到书店去找一找,依葫芦化瓢,不出10天就会了,如果深入一些,将无量...
如果你只是偶尔写一点就不必那么费力了,如果你想深入地用Delphi进行网络编程,建议你到书店去找一找,依葫芦化瓢,不出10天就会了,如果深入一些,将无量...
#20
嗯,谢谢,可是这样不好阿,遇到问题解决不了,总是有点嘎达嘎大的感觉。。
哎。。
哎。。
#21
如果是程序的某一个地方出问题,改动量小的话,就立马可以解决,问题是当一个问题头绪多乱或者不是三言两语能说清楚的话,就只能靠自己去学习了,旁人只能指个路。
相比之下,有个人指个方向,学习的进度就大不一样了。
相比之下,有个人指个方向,学习的进度就大不一样了。
#22
哎,那倒是,哦,你有油箱嘛?要不我发完整程序给你看看吧?谢谢。