基于Udp的局域网聊天 本帖最后由 yklovelife 于 2009-11-30 15:14:36 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 源码如下:unit Main;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons,WinSock;type TForm1 = class(TForm) edtIP: TEdit; btnSend: TBitBtn; mmo1: TMemo; edtMsg: TEdit; lblIP: TLabel; mmo2: TMemo; procedure btnSendClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; procedure ServerReader(s:TSocket);var Form1: TForm1; sockSrv:TSocket;//接受线程 buf:array[0..100] of Char; trdHandle:THandle;//当前线程句柄 trdOutHand:THandle;//Out Handleimplementationuses SockRdTrd;{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);var addrClient:sockaddr_in; sendSize:Integer;//SIZE OF addrClient acThreadID:DWORD;//线程ID wsd:TWSAData; addrSrv:sockaddr_in; nRet:Integer;//返回的结果 wVersionRequested:Word;//WinSock版本begin wVersionRequested:=MakeWord(2,1); if WSAStartup(wVersionRequested,wsd)<>0 then //加载DLL begin ShowMessage('加载失败!'); Exit; end; //创建套接字 sockSrv:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if sockSrv=INVALID_SOCKET then begin ShowMessage('创建失败!'); WSACleanup; Exit; end; //设置服务器地址 ZeroMemory(@buf[0],BUF_SIZE); addrSrv.sin_addr.S_addr:=htonl(INADDR_ANY); addrSrv.sin_family:=AF_INET; addrSrv.sin_port:=htons(5000); //绑定套接字 nRet:=bind(sockSrv,addrSrv,SizeOf(addrSrv)); if Socket_Error=nRet then begin ShowMessage('bind failed'); closesocket(sockSrv); WSACleanup; Exit; end; sendSize:=SizeOf(addrClient); trdHandle:=CreateThread(nil,0,@ServerReader,@sockSrv,0,acThreadID);end;procedure ServerReader(s:TSocket);var nRet:Integer;//返回结果 addrClient:sockaddr_in; sendSize:Integer; conAddr:string;//CLIENT IPbegin // 从客户端接收数据nonzero sendSize:=SizeOf(addrClient); //WaitForSingleObject(trdHandle,1000); while GetExitCodeThread(trdHandle,trdOutHand) do begin nRet := recvfrom(sockSrv,buf,SizeOf(buf),0,addrClient,sendSize); if nRet>0 then begin//打印来自客户端发送的数据 conAddr:=inet_ntoa(addrClient.sin_addr); Form1.mmo1.Lines.Add('来自 '+conAddr+'的消息: '+buf); end; end;end;//Clientprocedure TForm1.btnSendClick(Sender: TObject);var wsd:TWSAData; s:TSocket; nRet,sockClient:Integer; buf:array[0..100] of Char; servAddr:sockaddr_in; nServAddrLen:Integer;begin //加载DLL if WSAStartup(MakeWord(2,1),wsd)<>0 then begin ShowMessage('WSAStartup failes!'); Exit; end; //初始化套接字 s:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if S=INVALID_SOCKET then begin ShowMessage(Format('socket() failed ,Error Code :%d',[WSAGetLastError])); WSACleanup; Exit; end; sockClient:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); ZeroMemory(@buf[0],100); //为什么要填补内存块 //设置服务器地址 servAddr.sin_family:=AF_INET; servAddr.sin_addr.S_addr:=inet_addr(PChar(edtIP.Text)); servAddr.sin_port:=htons(5000); //向服务器发送数据 nServAddrLen:=SizeOf(servAddr); StrCopy(buf,PChar(edtMsg.Text)); nRet:=sendto(sockClient,buf,100,0,servAddr,nServAddrLen); if nRet=SOCKET_ERROR then begin ShowMessage(Format('recvfrom() failed',[WSAGetLastError])); closesocket(s); WSACleanup(); Exit; end; closesocket(s); WSACleanup();end;end. 直接这样不是创建一个线程吗?CreateThread(nil,0,@ServerReader,@sockSrv,0,acThreadID); 我自己也不知道。请指点下。 你服务端始终使用的是第一次连接大客户端socket,所以只能收到第一个人的,你需要维护一个客户端列表,然后创建一个线程,去循环扫描客户端socket列表,这需要用到WinSock.select功能去选择一个连接,然后读取这个链接发送的数据 代码写的。。初始化了俩次1.现在问题出在不能实现多客户端连接发送消息,貌似我创建的线程没起作用,或者我的写法本身有问题 线程开始就运行完估计你都还没发送包出去自己4.不用任何控件,要用线程,但不能使用线程类Thread。却到线程里 Form1.mmo1.Lines.Add('来自 '+conAddr+'的消息: '+buf); 明明只是这只是个简单的socket程序,你把接收代码放到发送后就可以了你自己估计连客户端和服务端都没清楚, 你说的思路我大体明白了,但请问下,具体该如何用DEMO实现,伪代码也可以,有个小小的提示就好,1.需要维护一个客户端列表2.然后创建一个线程,去循环扫描客户端socket列表能否帮我写几句关键代码。 你要UDP的还是TCP的?TCP的写得比较简单,只是一个模型。UDP的是网上的一个例子,功能比较全,TCP的是一对多的,UDP的是点对点的 我需要的是UDP的,我就需要的是点对点的效果。 请教下 "稻草人"你给我发的程序,server和client分别定义了一个同样的 消息过程。procedure WMSOCKET(var msg: TMessage);message WM_SOCKET;而且所有数据包,都是在这个 procedure中完成的,请问这是 如何 通信的。WMSOCKET 并 没有在任何地方被调用。 你之前的一个贴子,我贴了代码,并且作了详细的注释及说明,你干嘛不认真看一下? if SOCKET_ERROR=WSAAsyncSelect(SkC,Handle,WM_CLIENTSOCK,FD_READ or FD_CLOSE) then ShowMessage('WM_SOCKET Error');这句话,指明了使用网络消息事件进行通信的TCP和UDP是一样的,只是一个是无连接,一个是有连接的通信而已... 请大侠mdejtod也给我传一份啊。狠狠的顶你一下啊![email protected] 如何完全释放DLL窗体?让他再次打开时还和第一次一样 在Dll中新建两个窗口,要求第一个窗口能调用到第二个窗口中的数据。代码如下,但是出错了 treeview控件 请教intraweb7.0 下如何在窗体左边加一个框架(iwFrame); 在Delphi里怎样调用VB的控件MSComm 在delphi中button中如何实现文本换行? 关于调用程序的问题!!?? tadoquery的怪问题! 将Excel文件数据另存为Txt文件 在panel上放置media player 关于WEBSERVICE服务调用的问题 【CSDN开心辞典】Delphi版哪几位拥有进士牌牌?
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons,WinSock;
type
TForm1 = class(TForm)
edtIP: TEdit;
btnSend: TBitBtn;
mmo1: TMemo;
edtMsg: TEdit;
lblIP: TLabel;
mmo2: TMemo;
procedure btnSendClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure ServerReader(s:TSocket);
var
Form1: TForm1;
sockSrv:TSocket;//接受线程
buf:array[0..100] of Char;
trdHandle:THandle;//当前线程句柄
trdOutHand:THandle;//Out Handle
implementation
uses SockRdTrd;
{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
var
addrClient:sockaddr_in;
sendSize:Integer;//SIZE OF addrClient
acThreadID:DWORD;//线程ID
wsd:TWSAData;
addrSrv:sockaddr_in;
nRet:Integer;//返回的结果
wVersionRequested:Word;//WinSock版本
begin
wVersionRequested:=MakeWord(2,1);
if WSAStartup(wVersionRequested,wsd)<>0 then //加载DLL
begin
ShowMessage('加载失败!');
Exit;
end;
//创建套接字
sockSrv:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if sockSrv=INVALID_SOCKET then
begin
ShowMessage('创建失败!');
WSACleanup;
Exit;
end;
//设置服务器地址
ZeroMemory(@buf[0],BUF_SIZE);
addrSrv.sin_addr.S_addr:=htonl(INADDR_ANY);
addrSrv.sin_family:=AF_INET;
addrSrv.sin_port:=htons(5000);
//绑定套接字
nRet:=bind(sockSrv,addrSrv,SizeOf(addrSrv));
if Socket_Error=nRet then
begin
ShowMessage('bind failed');
closesocket(sockSrv);
WSACleanup;
Exit;
end;
sendSize:=SizeOf(addrClient);
trdHandle:=CreateThread(nil,0,@ServerReader,@sockSrv,0,acThreadID);
end;
procedure ServerReader(s:TSocket);
var
nRet:Integer;//返回结果
addrClient:sockaddr_in;
sendSize:Integer;
conAddr:string;//CLIENT IP
begin
// 从客户端接收数据nonzero
sendSize:=SizeOf(addrClient);
//WaitForSingleObject(trdHandle,1000);
while GetExitCodeThread(trdHandle,trdOutHand) do
begin
nRet := recvfrom(sockSrv,buf,SizeOf(buf),0,addrClient,sendSize);
if nRet>0 then
begin//打印来自客户端发送的数据
conAddr:=inet_ntoa(addrClient.sin_addr);
Form1.mmo1.Lines.Add('来自 '+conAddr+'的消息: '+buf);
end;
end;
end;
//Client
procedure TForm1.btnSendClick(Sender: TObject);
var
wsd:TWSAData;
s:TSocket;
nRet,sockClient:Integer;
buf:array[0..100] of Char;
servAddr:sockaddr_in;
nServAddrLen:Integer;
begin
//加载DLL
if WSAStartup(MakeWord(2,1),wsd)<>0 then
begin
ShowMessage('WSAStartup failes!');
Exit;
end;
//初始化套接字
s:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if S=INVALID_SOCKET then
begin
ShowMessage(Format('socket() failed ,Error Code :%d',[WSAGetLastError]));
WSACleanup;
Exit;
end;
sockClient:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
ZeroMemory(@buf[0],100); //为什么要填补内存块
//设置服务器地址
servAddr.sin_family:=AF_INET;
servAddr.sin_addr.S_addr:=inet_addr(PChar(edtIP.Text));
servAddr.sin_port:=htons(5000);
//向服务器发送数据
nServAddrLen:=SizeOf(servAddr);
StrCopy(buf,PChar(edtMsg.Text));
nRet:=sendto(sockClient,buf,100,0,servAddr,nServAddrLen);
if nRet=SOCKET_ERROR then
begin
ShowMessage(Format('recvfrom() failed',[WSAGetLastError]));
closesocket(s);
WSACleanup();
Exit;
end;
closesocket(s);
WSACleanup();
end;
end.
CreateThread(nil,0,@ServerReader,@sockSrv,0,acThreadID);
我自己也不知道。请指点下。
1.现在问题出在不能实现多客户端连接发送消息,貌似我创建的线程没起作用,或者我的写法本身有问题
线程开始就运行完估计你都还没发送包出去
自己4.不用任何控件,要用线程,但不能使用线程类Thread。
却到线程里 Form1.mmo1.Lines.Add('来自 '+conAddr+'的消息: '+buf);
明明只是这只是个简单的socket程序,你把接收代码放到发送后就可以了
你自己估计连客户端和服务端都没清楚,
1.需要维护一个客户端列表
2.然后创建一个线程,去循环扫描客户端socket列表
能否帮我写几句关键代码。
TCP的是一对多的,UDP的是点对点的
procedure WMSOCKET(var msg: TMessage);message WM_SOCKET;
而且所有数据包,都是在这个 procedure中完成的,请问这是 如何 通信的。WMSOCKET 并 没有在任何地方被调用。
if SOCKET_ERROR=WSAAsyncSelect(SkC,Handle,WM_CLIENTSOCK,FD_READ or FD_CLOSE) then
ShowMessage('WM_SOCKET Error');
这句话,指明了使用网络消息事件进行通信的TCP和UDP是一样的,只是一个是无连接,一个是有连接的通信而已...
也给我传一份啊。狠狠的顶你一下啊!
[email protected]