服务端端代码: var ErrorCode,AddrSize : integer; FSock : TSocket; SockAddr_In,Add: TSockAddrIn; nrev:Integer; revMsg:array[0..1024] of Char; begin winsock.WSAStartup($0101,WSADATA); FSock := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if FSock = SOCKET_ERROR then begin showmessage('创建套接字失败' ); Exit; end; SockAddr_In.sin_family := AF_INET; SockAddr_In.sin_port := htonl(9315); SockAddr_In.sin_addr.S_addr := htonl(INADDR_ANY); ErrorCode := bind(FSock,SockAddr_In,sizeof(SockAddr_In)); if ErrorCode = SOCKET_ERROR then begin showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) ); Exit; end; while true do begin nrev:=recv(FSock,FBuf,1024,1); //为什么nrev的返回值一直为-1 if nrev>0 then begin test:=inet_ntoa(Add.sin_addr); ShowMessage('接受到来自:'+inet_ntoa(Add.sin_addr)); end; end; closesocket(FSock); end; 客户端代码 procedure TForm1.Button1Click(Sender: TObject); var ErrorCode:Integer; msg:array[0..100] of Char; SockAdd_Inc:TSockAddrIn; Skc:TSocket; begin ErrorCode:=WSAStartup($0101,WSAData); if ErrorCode<>0 then begin ShowMessage('加载WinSock DLL失败!'); end; Skc:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if Skc=SOCKET_ERROR then begin ShowMessage('创建套接字失败!'); Exit; end; SockAdd_Inc.sin_family:=AF_INET; SockAdd_Inc.sin_port:=9315; SockAdd_Inc.sin_addr.S_addr:=inet_addr(PChar('192.168.1.90')); msg:='Test'; sendto(Skc,msg,SizeOf(msg),1,SockAdd_Inc,SizeOf(SockAdd_Inc)); closesocket(Skc); end;
给你我写的个例子吧,不过用的不是阻塞模式unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,WinSock, Buttons; const WM_SERVERSOCK = WM_USER + 100; WM_CORRESPONDSOCK = WM_USER + 101; WM_CLIENTSOCK = WM_USER + 102; type TForm1 = class(TForm) chkLock: TCheckBox; btn1: TButton; btn2: TButton; mmo1: TMemo; edtSever: TEdit; btnSever: TSpeedButton; edtClient: TEdit; btnClient: TSpeedButton; btnServerClose: TButton; btnClientClose: TButton; btn3: TButton; procedure btn1Click(Sender: TObject); procedure btn2Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure btnSeverClick(Sender: TObject); procedure btnClientClick(Sender: TObject); procedure btnServerCloseClick(Sender: TObject); procedure btnClientCloseClick(Sender: TObject); private { Private declarations } public { Public declarations } procedure WMSERVERSOCK(var message : TMessage); message WM_SERVERSOCK; procedure WMCORRESPONDSOCK(var message : TMessage); message WM_CORRESPONDSOCK; procedure WMCLIENTSOCK(var message : TMessage); message WM_CLIENTSOCK; end; TSockReadThread= class(TThread) private FSocket : TSocket; FBuf : array[0..255] of Char; FMemo : TMemo; procedure GetResult; protected procedure Execute;override; public constructor Create(pSocket : TSocket;mm : TMemo); end; var Form1: TForm1; WSAData : TWSAData; FSock,AcceptSock, SkC : TSocket; pData : array[0..255] of Char; procedure StartUp; implementation{$R *.dfm} procedure StartUp; var ErrorCode : integer; begin //加载winSock dll ErrorCode := WSAStartup($0101, WSAData); if ErrorCode <> 0 then begin ShowMessage('加载失败'); exit; end; end; { TSockReadThread }constructor TSockReadThread.Create(pSocket: TSocket; mm: TMemo); begin FMemo := mm; FSocket := pSocket; inherited Create(false); end;procedure TSockReadThread.Execute; var ret : integer; FdSet : TFDSet; TimeVal : TTimeVal; begin inherited; FreeOnTerminate := True; while not terminated do begin FD_ZERO(FdSet); FD_SET(FSocket,FdSet); TimeVal.tv_sec := 0; TimeVal.tv_usec := 500; if (select(0,@fdSet,nil,nil,@TimeVal) > 0) and not terminated then begin { 利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据 防止应用程序在套接字处于锁定模式中时,在一次I / O绑定调用(如send或recv)过程中, 被迫进入“锁定”状态;同时防止在套接字处于非锁定模式中时,产生WSAEWOULDBLOCK错误。 除非满足事先用参数规定的条件,否则select函数会在进行I/O操作时锁定 } ret := recv(FSocket,fbuf,256,0); if ret > 0 then Synchronize(GetResult) else Break; end; end; end;procedure TSockReadThread.GetResult; begin FMemo.Lines.Add(FBuf); end;procedure TForm1.btn1Click(Sender: TObject); var ErrorCode,AddSize : integer; SockAdd_In,Add: TSockAddrIn; tm : Longint; FdSet : TFDSet; TimeVal : TTimeVal; buf : array[0..9] of Char; begin //创建一个使用TCP协议的套接字 SOCK_STREAM IPPROTO_TCP FSock := socket(PF_INET,SOCK_STREAM , IPPROTO_TCP); if FSock = SOCKET_ERROR then begin showmessage(Format('%s;ErrorCode:%d',['套接字创建失败',WSAGetLastError]) ); Exit; end; //根据一个TCheckBox控件的选择情况来决定使用锁定模式还是非锁定模式 if chkLock.Checked then tm := 1 //非锁定模式 else tm := 0; //锁定模式 { 在锁定模式下,在I/O操作完成前,执行操作的Winsock函数(比如send和recv)会一直等候下去,不会立即返回程序 (将控制权交还给程序)。而在非锁定模式下, Winsock函数无论如何都会立即返回。 在阻塞模式下,当没有客户端请求发送时,调用accept函数的线程(这里是主线程)将一直阻塞下去,不会返回 在非锁定模式下 Winsock API调用会立即返回。大多数情况下,这些调用都会“失败”,并返回一个WSAEWOULDBLOCK错误。 它意味着请求的操作在调用期间没有时间完成。需要重复调用同一个函数,直至获得一个成功返回代码 } ioctlsocket(FSock,FIONBIO,tm); { FIONBIO : 该命令可在套接字s上允许或禁止“非锁定”(Nonblocking)模式 ,argp 为非0 表示非锁定 为0 表示锁定 FIONREAD : 用于决定可从套接字上自动读入的数据量 } SockAdd_In.sin_family := PF_INET; SockAdd_In.sin_port := htons(5151); SockAdd_In.sin_addr.S_addr := INADDR_ANY; //允许服务器应用监听主机计算机上面每个网络接口上的客户机活动 //绑定 ErrorCode := bind(FSock,SockAdd_In,sizeof(SockAdd_In)); if ErrorCode = SOCKET_ERROR then begin showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) ); Exit; end; //置为监听模式 backlog参数指定了正在等待连接的最大队列长度 listen(FSock,5); //调用WSAAsyncSelect或WSAEventSelect函数的时候,会将套接字自动设为非锁定模式 if SOCKET_ERROR=WSAAsyncSelect(FSock,Handle,WM_SERVERSOCK,FD_READ or FD_ACCEPT) then ShowMessage('WM_SOCKET Error'); end;procedure TForm1.btn2Click(Sender: TObject); var buf : array[0..10] of Char; SockAdd_Inc : TSockAddrIn; begin // SOCK_STREAM IPPROTO_TCP skc := socket(PF_INET,SOCK_STREAM , IPPROTO_TCP); if skc = SOCKET_ERROR then begin showmessage('创建失败'); Exit; end; SockAdd_Inc.sin_family := PF_INET; SockAdd_Inc.sin_port := htons(5151); SockAdd_Inc.sin_addr.S_addr := inet_addr(pchar('127.0.0.1')); //服务端地址 connect(skc,SockAdd_Inc,sizeof(SockAdd_Inc)); if SOCKET_ERROR=WSAAsyncSelect(SkC,Handle,WM_CLIENTSOCK,FD_READ or FD_CLOSE) then ShowMessage('WM_SOCKET Error'); end; //与客户端连接后的SOCK所产生的网络事件 procedure TForm1.WMCORRESPONDSOCK(var message: TMessage); var ret : integer; fbuf : array[0..255] of Char; begin case WSAGetSelectEvent(message.LParam) of FD_CLOSE : begin mmo1.Lines.Add('客户端关闭'); end; FD_READ : begin ret := recv(AcceptSock,fbuf,256,0); mmo1.Lines.Add('客户端来的消息 : ' + fbuf); end; end; end; //监视SOCK 所产生的网络消息事件 procedure TForm1.WMSERVERSOCK(var message: TMessage); var FdSet : TFDSet; TimeVal : TTimeVal; AddSize : integer; Add: TSockAddrIn; begin case WSAGetSelectEvent(message.LParam) of FD_ACCEPT : begin //FD_ZERO(set) -- 将 set 的值清乾净 //FD_SET(s, *set) -- 将 s 加到 set 中 //FD_CLR(s, *set) -- 将 s 从 set 中删除 //FD_ISSET(s, *set) -- 检查 s 是否存在於 set 中 FD_ZERO(FdSet); FD_SET(FSock,FdSet); TimeVal.tv_sec := 0; TimeVal.tv_usec := 500; //检查一整组(set)的 sockets 是否可以读、写资料,也可以用来检查 socket 是否已和对方连接成功, //或者是对方是否已将相对的socket 关闭等 // if (select(0,@fdSet,nil,nil,@TimeVal) > 0) then //查询读写连接中断状态,此处无需要使用该判断 //果 timeout 设为「NULL」,那麽 select() 就会一直等到「至少」 //某一个 socket 的事件成立了才会 return // begin //如果 timeout 的值设为 {0, 0} (秒, 微秒)管有没有 socket 的事件成立,都会马上 return,而不会停留 AddSize := sizeof(Add); AcceptSock := accept(FSock,@Add,@AddSize); //返回值为一新的 Socket,此新建之 Socket 不可再用来接受其它的连接要求; //但是原先监听之 Socket 仍可接受其他人的连接要求 // ShowMessage(inet_ntoa(Add.sin_addr)); if AcceptSock <> INVALID_SOCKET then WSAAsyncSelect(AcceptSock,Handle,WM_CORRESPONDSOCK,FD_READ or FD_WRITE or FD_CLOSE); // end; end; end; end;procedure TForm1.FormDestroy(Sender: TObject); begin shutdown(skc,SD_SEND); closesocket(FSock); closesocket(skc); closesocket(AcceptSock); end;procedure TForm1.WMCLIENTSOCK(var message: TMessage); var ret : integer; fbuf : array[0..255] of Char; begin case WSAGetSelectEvent(message.LParam) of FD_CLOSE : begin shutdown(SkC,SD_BOTH) ; closesocket(SkC); mmo1.Lines.Add('服务器关闭'); end; FD_READ : begin ret := recv(SkC,fbuf,256,0); mmo1.Lines.Add('服务器端来的消息 :' + fbuf); end; end; end;procedure TForm1.btnSeverClick(Sender: TObject); begin FillChar(pData,Length(pData),0); StrCopy(pData,PChar(edtSever.Text)); send(AcceptSock,pData,Length(pData) * SizeOf(Char) ,0); end;procedure TForm1.btnClientClick(Sender: TObject); begin FillChar(pData,Length(pData),0); StrCopy(pData,PChar(edtClient.Text)); send(SkC,pData,Length(pData) * SizeOf(Char) ,0); { 呼叫 send 或 sendto 传送资料时,系统告知错误,且错误码为10035 WSAEWOULDBLOCK(呼叫 WSAGetLastError 得知这项错误), 这时表示 output buffer 已经满了,无法再写入任何资料(此时即令呼叫再多次的send 也都一定失败); 一旦系统将部份资料成功送抵对方,空出 output buffer後,便会送一个 FD_WRITE 给使用者, 告知可继续传送资料了。换句话说,在呼叫 send 传送资料时,只要不是返回错误 10035 的话, 便可一直继续呼叫 send 来传送资料;一旦 send 回返错误 10035,那麽便不要再呼叫 send传送资料, 而须等收到 FD_WRITE 後,再继续传送资料。 } end;procedure TForm1.btnServerCloseClick(Sender: TObject); begin shutdown(AcceptSock,SD_BOTH); closesocket(AcceptSock); end;procedure TForm1.btnClientCloseClick(Sender: TObject); begin //断开连接 how参数可以是下面的任何一个值: SD_RECEIVE、SD_SEND或SD_BOTH。如果是SD_RECEIVE, //就表示不允许再调用接收函数 shutdown(SkC,SD_BOTH); closesocket(SkC) end;initialization StartUp; finalization WSACleanup; end.
var
ErrorCode,AddrSize : integer;
FSock : TSocket;
SockAddr_In,Add: TSockAddrIn;
nrev:Integer;
revMsg:array[0..1024] of Char;
begin
winsock.WSAStartup($0101,WSADATA);
FSock := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if FSock = SOCKET_ERROR then
begin
showmessage('创建套接字失败' );
Exit;
end;
SockAddr_In.sin_family := AF_INET;
SockAddr_In.sin_port := htonl(9315);
SockAddr_In.sin_addr.S_addr := htonl(INADDR_ANY);
ErrorCode := bind(FSock,SockAddr_In,sizeof(SockAddr_In));
if ErrorCode = SOCKET_ERROR then
begin
showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) );
Exit;
end;
while true do
begin nrev:=recv(FSock,FBuf,1024,1); //为什么nrev的返回值一直为-1
if nrev>0 then
begin
test:=inet_ntoa(Add.sin_addr);
ShowMessage('接受到来自:'+inet_ntoa(Add.sin_addr));
end;
end;
closesocket(FSock);
end;
客户端代码
procedure TForm1.Button1Click(Sender: TObject);
var
ErrorCode:Integer;
msg:array[0..100] of Char;
SockAdd_Inc:TSockAddrIn;
Skc:TSocket;
begin
ErrorCode:=WSAStartup($0101,WSAData);
if ErrorCode<>0 then
begin
ShowMessage('加载WinSock DLL失败!');
end;
Skc:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if Skc=SOCKET_ERROR then
begin
ShowMessage('创建套接字失败!');
Exit;
end;
SockAdd_Inc.sin_family:=AF_INET;
SockAdd_Inc.sin_port:=9315;
SockAdd_Inc.sin_addr.S_addr:=inet_addr(PChar('192.168.1.90'));
msg:='Test';
sendto(Skc,msg,SizeOf(msg),1,SockAdd_Inc,SizeOf(SockAdd_Inc));
closesocket(Skc);
end;
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,WinSock, Buttons;
const
WM_SERVERSOCK = WM_USER + 100;
WM_CORRESPONDSOCK = WM_USER + 101;
WM_CLIENTSOCK = WM_USER + 102;
type
TForm1 = class(TForm)
chkLock: TCheckBox;
btn1: TButton;
btn2: TButton;
mmo1: TMemo;
edtSever: TEdit;
btnSever: TSpeedButton;
edtClient: TEdit;
btnClient: TSpeedButton;
btnServerClose: TButton;
btnClientClose: TButton;
btn3: TButton;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnSeverClick(Sender: TObject);
procedure btnClientClick(Sender: TObject);
procedure btnServerCloseClick(Sender: TObject);
procedure btnClientCloseClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure WMSERVERSOCK(var message : TMessage); message WM_SERVERSOCK;
procedure WMCORRESPONDSOCK(var message : TMessage); message WM_CORRESPONDSOCK;
procedure WMCLIENTSOCK(var message : TMessage); message WM_CLIENTSOCK;
end;
TSockReadThread= class(TThread)
private
FSocket : TSocket;
FBuf : array[0..255] of Char;
FMemo : TMemo;
procedure GetResult;
protected
procedure Execute;override;
public
constructor Create(pSocket : TSocket;mm : TMemo);
end;
var
Form1: TForm1;
WSAData : TWSAData;
FSock,AcceptSock, SkC : TSocket;
pData : array[0..255] of Char;
procedure StartUp;
implementation{$R *.dfm}
procedure StartUp;
var
ErrorCode : integer;
begin
//加载winSock dll
ErrorCode := WSAStartup($0101, WSAData);
if ErrorCode <> 0 then
begin
ShowMessage('加载失败');
exit;
end;
end;
{ TSockReadThread }constructor TSockReadThread.Create(pSocket: TSocket; mm: TMemo);
begin
FMemo := mm;
FSocket := pSocket;
inherited Create(false);
end;procedure TSockReadThread.Execute;
var
ret : integer;
FdSet : TFDSet;
TimeVal : TTimeVal;
begin
inherited;
FreeOnTerminate := True;
while not terminated do
begin
FD_ZERO(FdSet);
FD_SET(FSocket,FdSet);
TimeVal.tv_sec := 0;
TimeVal.tv_usec := 500;
if (select(0,@fdSet,nil,nil,@TimeVal) > 0) and not terminated then
begin
{
利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据
防止应用程序在套接字处于锁定模式中时,在一次I / O绑定调用(如send或recv)过程中,
被迫进入“锁定”状态;同时防止在套接字处于非锁定模式中时,产生WSAEWOULDBLOCK错误。
除非满足事先用参数规定的条件,否则select函数会在进行I/O操作时锁定
}
ret := recv(FSocket,fbuf,256,0); if ret > 0 then Synchronize(GetResult)
else Break;
end;
end;
end;procedure TSockReadThread.GetResult;
begin
FMemo.Lines.Add(FBuf);
end;procedure TForm1.btn1Click(Sender: TObject);
var
ErrorCode,AddSize : integer;
SockAdd_In,Add: TSockAddrIn;
tm : Longint;
FdSet : TFDSet;
TimeVal : TTimeVal;
buf : array[0..9] of Char;
begin
//创建一个使用TCP协议的套接字 SOCK_STREAM IPPROTO_TCP
FSock := socket(PF_INET,SOCK_STREAM , IPPROTO_TCP);
if FSock = SOCKET_ERROR then
begin
showmessage(Format('%s;ErrorCode:%d',['套接字创建失败',WSAGetLastError]) );
Exit;
end;
//根据一个TCheckBox控件的选择情况来决定使用锁定模式还是非锁定模式
if chkLock.Checked then
tm := 1 //非锁定模式
else tm := 0; //锁定模式
{
在锁定模式下,在I/O操作完成前,执行操作的Winsock函数(比如send和recv)会一直等候下去,不会立即返回程序
(将控制权交还给程序)。而在非锁定模式下, Winsock函数无论如何都会立即返回。
在阻塞模式下,当没有客户端请求发送时,调用accept函数的线程(这里是主线程)将一直阻塞下去,不会返回
在非锁定模式下 Winsock API调用会立即返回。大多数情况下,这些调用都会“失败”,并返回一个WSAEWOULDBLOCK错误。
它意味着请求的操作在调用期间没有时间完成。需要重复调用同一个函数,直至获得一个成功返回代码
}
ioctlsocket(FSock,FIONBIO,tm);
{
FIONBIO : 该命令可在套接字s上允许或禁止“非锁定”(Nonblocking)模式 ,argp 为非0 表示非锁定 为0 表示锁定
FIONREAD : 用于决定可从套接字上自动读入的数据量
}
SockAdd_In.sin_family := PF_INET;
SockAdd_In.sin_port := htons(5151);
SockAdd_In.sin_addr.S_addr := INADDR_ANY; //允许服务器应用监听主机计算机上面每个网络接口上的客户机活动
//绑定
ErrorCode := bind(FSock,SockAdd_In,sizeof(SockAdd_In)); if ErrorCode = SOCKET_ERROR then
begin
showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) );
Exit;
end;
//置为监听模式 backlog参数指定了正在等待连接的最大队列长度
listen(FSock,5);
//调用WSAAsyncSelect或WSAEventSelect函数的时候,会将套接字自动设为非锁定模式
if SOCKET_ERROR=WSAAsyncSelect(FSock,Handle,WM_SERVERSOCK,FD_READ or FD_ACCEPT) then
ShowMessage('WM_SOCKET Error');
end;procedure TForm1.btn2Click(Sender: TObject);
var
buf : array[0..10] of Char;
SockAdd_Inc : TSockAddrIn;
begin // SOCK_STREAM IPPROTO_TCP
skc := socket(PF_INET,SOCK_STREAM , IPPROTO_TCP);
if skc = SOCKET_ERROR then
begin
showmessage('创建失败');
Exit;
end;
SockAdd_Inc.sin_family := PF_INET;
SockAdd_Inc.sin_port := htons(5151);
SockAdd_Inc.sin_addr.S_addr := inet_addr(pchar('127.0.0.1')); //服务端地址
connect(skc,SockAdd_Inc,sizeof(SockAdd_Inc));
if SOCKET_ERROR=WSAAsyncSelect(SkC,Handle,WM_CLIENTSOCK,FD_READ or FD_CLOSE) then
ShowMessage('WM_SOCKET Error');
end;
//与客户端连接后的SOCK所产生的网络事件
procedure TForm1.WMCORRESPONDSOCK(var message: TMessage);
var
ret : integer;
fbuf : array[0..255] of Char;
begin
case WSAGetSelectEvent(message.LParam) of
FD_CLOSE :
begin
mmo1.Lines.Add('客户端关闭');
end;
FD_READ :
begin
ret := recv(AcceptSock,fbuf,256,0);
mmo1.Lines.Add('客户端来的消息 : ' + fbuf);
end;
end;
end;
//监视SOCK 所产生的网络消息事件
procedure TForm1.WMSERVERSOCK(var message: TMessage);
var FdSet : TFDSet;
TimeVal : TTimeVal;
AddSize : integer;
Add: TSockAddrIn;
begin
case WSAGetSelectEvent(message.LParam) of
FD_ACCEPT :
begin
//FD_ZERO(set) -- 将 set 的值清乾净
//FD_SET(s, *set) -- 将 s 加到 set 中
//FD_CLR(s, *set) -- 将 s 从 set 中删除
//FD_ISSET(s, *set) -- 检查 s 是否存在於 set 中
FD_ZERO(FdSet);
FD_SET(FSock,FdSet);
TimeVal.tv_sec := 0;
TimeVal.tv_usec := 500; //检查一整组(set)的 sockets 是否可以读、写资料,也可以用来检查 socket 是否已和对方连接成功,
//或者是对方是否已将相对的socket 关闭等
// if (select(0,@fdSet,nil,nil,@TimeVal) > 0) then //查询读写连接中断状态,此处无需要使用该判断
//果 timeout 设为「NULL」,那麽 select() 就会一直等到「至少」
//某一个 socket 的事件成立了才会 return
// begin //如果 timeout 的值设为 {0, 0} (秒, 微秒)管有没有 socket 的事件成立,都会马上 return,而不会停留
AddSize := sizeof(Add);
AcceptSock := accept(FSock,@Add,@AddSize); //返回值为一新的 Socket,此新建之 Socket 不可再用来接受其它的连接要求;
//但是原先监听之 Socket 仍可接受其他人的连接要求
// ShowMessage(inet_ntoa(Add.sin_addr));
if AcceptSock <> INVALID_SOCKET then
WSAAsyncSelect(AcceptSock,Handle,WM_CORRESPONDSOCK,FD_READ or FD_WRITE or FD_CLOSE);
// end;
end;
end;
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
shutdown(skc,SD_SEND);
closesocket(FSock);
closesocket(skc);
closesocket(AcceptSock);
end;procedure TForm1.WMCLIENTSOCK(var message: TMessage);
var
ret : integer;
fbuf : array[0..255] of Char;
begin
case WSAGetSelectEvent(message.LParam) of
FD_CLOSE :
begin
shutdown(SkC,SD_BOTH) ;
closesocket(SkC);
mmo1.Lines.Add('服务器关闭');
end;
FD_READ :
begin
ret := recv(SkC,fbuf,256,0);
mmo1.Lines.Add('服务器端来的消息 :' + fbuf);
end;
end;
end;procedure TForm1.btnSeverClick(Sender: TObject);
begin
FillChar(pData,Length(pData),0);
StrCopy(pData,PChar(edtSever.Text));
send(AcceptSock,pData,Length(pData) * SizeOf(Char) ,0);
end;procedure TForm1.btnClientClick(Sender: TObject);
begin
FillChar(pData,Length(pData),0);
StrCopy(pData,PChar(edtClient.Text));
send(SkC,pData,Length(pData) * SizeOf(Char) ,0);
{
呼叫 send 或 sendto 传送资料时,系统告知错误,且错误码为10035 WSAEWOULDBLOCK(呼叫 WSAGetLastError 得知这项错误),
这时表示 output buffer 已经满了,无法再写入任何资料(此时即令呼叫再多次的send 也都一定失败);
一旦系统将部份资料成功送抵对方,空出 output buffer後,便会送一个 FD_WRITE 给使用者,
告知可继续传送资料了。换句话说,在呼叫 send 传送资料时,只要不是返回错误 10035 的话,
便可一直继续呼叫 send 来传送资料;一旦 send 回返错误 10035,那麽便不要再呼叫 send传送资料,
而须等收到 FD_WRITE 後,再继续传送资料。
}
end;procedure TForm1.btnServerCloseClick(Sender: TObject);
begin
shutdown(AcceptSock,SD_BOTH);
closesocket(AcceptSock);
end;procedure TForm1.btnClientCloseClick(Sender: TObject);
begin
//断开连接 how参数可以是下面的任何一个值: SD_RECEIVE、SD_SEND或SD_BOTH。如果是SD_RECEIVE,
//就表示不允许再调用接收函数
shutdown(SkC,SD_BOTH);
closesocket(SkC)
end;initialization
StartUp;
finalization
WSACleanup;
end.
const
BUF_SIZE = 64;
var
wsd: TWSADATA;
s: TSOCKET;
nRet, socketSrv: Integer;
addrClient, addrSrv: SOCKADDR_IN;
buf: array[0..BUF_SIZE] of Char;
len: Integer;
begin
// 初始化套接字动态库
if WSAStartup(MAKEWORD(2, 2), wsd) <> 0 then
begin
ShowMessage('WSAStartup failed !');
Exit;
end; // 创建套接字
S := socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then
begin
ShowMessage(Format('socket() failed ,Error Code: %d', [WSAGetLastError]));
WSACleanup();
Exit;
end; socketSrv := socket(AF_INET, SOCK_DGRAM, 0); len := sizeof(SOCKADDR); // 设置服务器地址
ZeroMemory(@buf[0], BUF_SIZE);
addrSrv.sin_addr.S_addr := htonl(INADDR_ANY);
// addrSrv.sin_addr.S_un.S_addr := htonl(INADDR_ANY);
addrSrv.sin_family := AF_INET;
addrSrv.sin_port := htons(5000); // 绑定套接字
nRet := bind(socketSrv, PSOCKADDR(@addrSrv), sizeof(SOCKADDR));
if (SOCKET_ERROR = nRet) then
begin
ShowMessage('bind failed !');
closesocket(s);
WSACleanup();
Exit
end; // 从客户端接收数据
nRet := recvfrom(socketSrv, buf, BUF_SIZE, 0, addrClient, len);
if (SOCKET_ERROR = nRet) then
begin
ShowMessage('recvfrom failed !');
closesocket(s);
WSACleanup();
end; // 打印来自客户端发送来的数据
ShowMessage('Recv From Client' + buf); // 向客户端发送数据
buf := 'UDP Hello World ';
sendto(socketSrv, buf, Length('UDP Hello World !'), 0, addrClient, len);
closesocket(s);
WSACleanup();
end;Clientconst
BUF_SIZE = 64;
var
wsd: TWSADATA;
s: TSOCKET;
nRet, sockClient: Integer;
servAddr, addrSrv: SOCKADDR_IN;
buf: array[0..BUF_SIZE] of Char;
nServAddLen: Integer;
begin
// 初始化套接字动态库
if WSAStartup(MAKEWORD(2, 2), wsd) <> 0 then
begin
ShowMessage('WSAStartup failed !');
Exit;
end; // 创建套接字
S := socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then
begin
ShowMessage(Format('socket() failed ,Error Code: %d', [WSAGetLastError]));
WSACleanup();
Exit;
end; sockClient := socket(AF_INET, SOCK_DGRAM, 0);
ZeroMemory(@buf[0], BUF_SIZE);
StrCopy(buf, 'UDP Hello World !'); // 设置服务器地址
servAddr.sin_family := AF_INET;
servAddr.sin_addr.S_addr := inet_addr('127.0.0.1');
servAddr.sin_port := htons(5000); // 向服务器发送数据
nServAddLen := sizeof(servAddr);
if (sendto(sockClient, buf, BUF_SIZE, 0, servAddr, nServAddLen) = SOCKET_ERROR)
then
begin
ShowMessage(Format('recvfrom() failed', [WSAGetLastError()]));
closesocket(s);
WSACleanup();
Exit;
end;
nRet := recvfrom(sockClient, buf, BUF_SIZE, 0, servAddr, nServAddLen);
if (SOCKET_ERROR = nRet) then
begin
ShowMessage('recvfrom failed !\n');
closesocket(s);
WSACleanup();
Exit;
end; // 打印来自服务端发送来的数据
ShowMessage('Recv From Server: ' + buf);
closesocket(s);
WSACleanup();
end;
服务器端:
1、SockAddr_In.sin_port := htonl(9315);
这里要改成 htons(9315);2、nrev:=recv(FSock,FBuf,1024,1); //为什么nrev的返回值一直为-1
因为 Recv的Flag不支持 1,要修改为0,不知道FBuf为何物,应该是这样吧?
nrev:=recv(FSock,RevMsg,1024,0); 另外,下面要取发过来的地址,应该采用recvFrom()
完整的代码应该是这样:var
ErrorCode, AddrSize : integer;
FSock : TSocket;
SockAddr_In,Add: TSockAddrIn;
nrev:Integer;
revMsg:array[0..1024] of Char;
Str : string;
WSADATA: TWSAData;
begin
winsock.WSAStartup($0101,WSADATA);
FSock := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if FSock = SOCKET_ERROR then
begin
showmessage('创建套接字失败' );
Exit;
end;
SockAddr_In.sin_family := AF_INET;
SockAddr_In.sin_port := htons(9315);
SockAddr_In.sin_addr.S_addr := INADDR_ANY;
ErrorCode := bind(FSock,SockAddr_In,sizeof(SockAddr_In));
if ErrorCode = SOCKET_ERROR then
begin
showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) );
Exit;
end;
while true do
begin
// nrev:=recv(FSock,revMsg,1024,0); //为什么nrev的返回值一直为-1
AddrSize := sizeof(Add);
nrev := RecvFrom(FSock, revMsg, 1024, 0, Add, AddrSize);
if nrev>0 then
begin
SetString(Str, revMsg, nRev);
ShowMessage('接收到来自:'+inet_ntoa(Add.sin_addr) + ': ' + Str);
Break;
end;
end;
closesocket(FSock);
WsaCLeanup;
ShowMessage('UDP服务测试结束');
end;
客户端:
1、SockAdd_Inc.sin_port:=9315;
改为
SockAdd_Inc.sin_port:=htons(9315);
2、sendto的Flag也不能用1完整的代码应该是这样:
var
ErrorCode:Integer;
msg:array[0..100] of Char;
SockAdd_Inc:TSockAddrIn;
Skc:TSocket;
WSAData: TWSAData;
begin
ErrorCode:=WSAStartup($0101,WSAData);
if ErrorCode <>0 then
begin
ShowMessage('加载WinSock DLL失败!');
end;
Skc:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if Skc=SOCKET_ERROR then
begin
ShowMessage('创建套接字失败!');
Exit;
end;
FillChar(SockAdd_Inc, sizeof(SockAdd_Inc), 0);
SockAdd_Inc.sin_family:=AF_INET;
SockAdd_Inc.sin_port:=htons(9315);
SockAdd_Inc.sin_addr.S_addr:=inet_addr('127.0.0.1');
StrPCopy(msg, 'Test');
ErrorCode := sendto(Skc,msg,StrLen(msg),0,SockAdd_Inc,SizeOf(SockAdd_Inc));
if ErrorCode < 0 then
begin
ShowMessage('发送失败!'+inttostr(WSAGetLastError()));
end;
closesocket(Skc);
wsaCleanup;
end;
SDK中这样解释Specifies the way in which the call is made.(指定以何种方式实现调用)
这个参数都可以填哪些值,什么情况下用哪些值。
"做线程的时候 不能用Delphi中的那个Thread类,那个性能不好,而且不利于移植,说是要自己写,"请问下哪位高手这样的话我该用什么,怎么用。也可以稍微提示下,我在查相关资料。子。我连菜鸟也够不上,最好能说的通俗点,谢谢了。
要是复杂了,我在另开个帖子,令加分。
我不知道你是在哪里找到跟我一模一样的代码的