Client和Server无法通讯,有什么问题请指正!(100分)

  • 主题发起人 主题发起人 cfjjj
  • 开始时间 开始时间
C

cfjjj

Unregistered / Unconfirmed
GUEST, unregistred user!
上次提了个关于UDP的Daytime的问题,zw84611专家给了个例程很不错。不过他给的
这个例程是将客户端和服务器放在一起的,工作挺正常。现在我把他们分了开来,结果
就不能通讯了,看了半天socket的书看得头都大了。现出100大洋,解放一下我的大脑,
请大家批评指正。
程序的基本思路是:1、服务器端先侦听;2、客户端发送一个"Want Daytime"字符串给
服务器;3、服务器收到后,作了判断看客户端发来的数据是不是"Want Daytime",如果
是则将服务器的日期和时间发送给客户端;4、客户端收到服务器发来的数据后,将其显
示在textbox中。注意:一定是用UDP协议;客户端和服务器可以运行在同一台机器上,
也可以运行在网络内的不同地方。
我分开的程序如下:
Client端
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, winsock,
StdCtrls;

const
WM_SOCK = WM_USER + 1; //自定义windows消息
UDPPORT = 55554; //设定UDP端口号

type
TForm1 = class(TForm)
EditReturnData: TEdit;
BtnStart: TButton;
BtnExit: TButton;
EditServerIP: TEdit;
Label1: TLabel;
procedure BtnStartClick(Sender: TObject);
procedure BtnExitClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
s: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn;
//利用消息实时获知UDP消息
procedure Daytime(var Message: TMessage);
message WM_SOCK;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
TempWSAData: TWSAData;
begin
// 初始化SOCKET
if WSAStartup($101, TempWSAData)=1 then
showmessage('StartUp Error!');
s := Socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then //Socket创建失败
begin
showmessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(s);
end;
//发送方SockAddr绑定
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
addr.sin_port := htons(UDPPORT);
if Bind(s, addr, sizeof(addr)) <> 0 then
begin
showmessage('bind fail');
end;
WSAAsyncSelect(s, form1.Handle , WM_SOCK, FD_READ);
//接收端SockAddrIn设定
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(55555);
end;

procedure TForm1.BtnStartClick(Sender: TObject);
var
buffer: Array [1..4096] of char;
len: integer;
flen: integer;
Event: word;
value: string;
begin
FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(EditServerIP.text)); //INADDR_BROADCAST; //INADDR_BROADCAST = -1 ?
value := 'Want Daytime';
len := sendto(s, value[1], Length(value), 0, FSockAddrIn, sizeof(FSockAddrIn));
if (WSAGetLastError() <> WSAEWOULDBLOCK) and (WSAGetLastError() <> 0) then
showmessage(inttostr(WSAGetLastError()));
if len = SOCKET_ERROR then
showmessage('send fail');
if len <> Length(value) then
showmessage('Not Send all');
end;

procedure Tform1.Daytime(var Message: TMessage);
var
buffer: Array [1..4096] of char;
len: integer;
flen: integer;
Event: word;
value: string;
begin
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Port := htons(UDPPORT);
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
value := copy(buffer, 1, len);
form1.EditReturnData.Text :=value;
end;
end;

procedure TForm1.BtnExitClick(Sender: TObject);
begin
CloseSocket(s);
form1.EditReturnData.Destroy ;
form1.BtnStart.Destroy;
form1.BtnExit.Destroy;
form1.EditServerIP.Destroy;
form1.Close;
form1.Destroy;
end;
end.

Server端
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, winsock,
StdCtrls;

const
WM_SOCK = WM_USER + 1; //自定义windows消息
UDPPORT = 55555; //设定UDP端口号

type
TForm1 = class(TForm)
BtnStart: TButton;
BtnStop: TButton;
BtnExit: TButton;
procedure FormCreate(Sender: TObject);
procedure BtnStartClick(Sender: TObject);
procedure BtnStopClick(Sender: TObject);
procedure BtnExitClick(Sender: TObject);
private
{ Private declarations }
s: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn;
//利用消息实时获知UDP消息
procedure Daytime(var Message: TMessage);
message WM_SOCK;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}



procedure TForm1.FormCreate(Sender: TObject);
begin
form1.BtnStart.Visible:=true;
btnstop.Visible:=false;
end;

procedure TForm1.BtnStartClick(Sender: TObject);
var
TempWSAData: TWSAData;
begin
form1.BtnStart.Visible:=false;
form1.BtnStop.Visible:=true;

// 初始化SOCKET
if WSAStartup($101, TempWSAData)=1 then
showmessage('StartUp Error!');
s := Socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then //Socket创建失败
begin
showmessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(s);
end;
//发送方SockAddr绑定
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
addr.sin_port := htons(UDPPORT);
if Bind(s, addr, sizeof(addr)) <> 0 then
begin
showmessage('bind fail');
end;
WSAAsyncSelect(s, form1.Handle , WM_SOCK, FD_READ);
//接收端SockAddrIn设定
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(55554);
end;

procedure TForm1.BtnStopClick(Sender: TObject);
begin
CloseSocket(s);
form1.BtnStart.Visible:=true;
form1.BtnStop.Visible:=false;
end;

procedure tform1.Daytime(var Message: TMessage);
var
buffer: Array [1..4096] of char;
len: integer;
flen: integer;
Event: word;
value: string;
remoteip:string;
begin
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Port := htons(UDPPORT);
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
value := copy(buffer, 1, len);
if value='Want Daytime' then
begin
getpeername(s,FSockAddrIn,sizeof(FSockAddrIn));
FSockAddrIn.sin_port:=htons(55554);
value := datetimetostr(now);
len := sendto(s, value[1], Length(value), 0, FSockAddrIn, sizeof(FSockAddrIn));
if (WSAGetLastError() <> WSAEWOULDBLOCK) and (WSAGetLastError() <> 0) then
showmessage(inttostr(WSAGetLastError()));
if len = SOCKET_ERROR then
showmessage('send fail');
if len <> Length(value) then
showmessage('Not Send all');
end;
end;
end;

procedure TForm1.BtnExitClick(Sender: TObject);
begin
CloseSocket(s);
form1.BtnStart.Destroy ;
form1.BtnStop.Destroy;
form1.BtnExit.Destroy;
form1.Close;
form1.Destroy;
end;

end.
 
哇,好长好多啊。。。。。我没看完。

用indy的控件组里的很容易啦
 
用控件那还不简单吗,10分钟就搞定了,现在就是不想用控件,就是想用socket
 
有控件为什么不用?像你这种简单的应用,控件都做得好好的。
为什么一定要。。。。。。证明自已的实力啊,还是在学习。。
我的想法是,简单的应用用控件解决,控件做不到的再用代码。
时间很宝贵啊。。
 
实在是不好意思,这是我们网络课的作业。平常我用控件都用惯了,不让用控件就没办法了!
所以请各位富翁帮忙。其实我做DELPHI程序也做了有两年多的时间了,一般的应用还真难
不倒我,现在这么一个简单的作业可还真把我给难住了!我用C#做了一个,基本完成了,可
我还是喜欢DELPHI,就想用DELPHI也做一个。而且因为有些人听到我想用DELPHI做这个作业
都不屑一顾,所以也是想为DELPHI证明一下。
 
两边的端口号要一样。
 
楼上说的好,呵呵端口号一定要一样啊
 
说清楚一点啊,什么两边端口号要一样啊!如果把所有端口号都设成一样,这样客户端和
服务器就没办法在一台机器上同时运行了!
 
你连不上说明端口问题啦
查查看就KO啦
 
>>客户端和服务器就没办法在一台机器上同时运行了
确实不行的。本来就是这样。就应该是两台机器!
 
可我用C#做的,客户端与服务器采用不同的端口号,在一台机器上就可以同时运行,
没有问题啊!难道DELPHI就是不如C#吗?
 
从来没看过这么菜的socket代码,呵呵。这样能连接就怪了。

打死我也不信在同一台机能够连接。建议先看看有关方面的书。
 
不同端 口号,肯定可以的,我在同一机器 上也试不通。
 
chenxz
这些code主要是zw84611写的,我只是把它分成了两个部分,你说菜那就是说他菜了。
他现在是大富翁第一名,你难道是第0名?再说了,当批评家谁不会啊?有本事你写
一段完美的code出来,让弟兄都跟你学习一下!
 
我真是想不到啊!如此简单的一个问题,在DELPHI的帮助里找不到答案,在大富翁里竟然
也难倒一堆人。看样子DELPHI程序员真的是没什么前途了,今后我还多花点时间在C#上吧!
微软最大的好处恐怕就是他永远也不会瞧不起新手,而是给新手以MSDN!
 
我来了...,抱歉,抱歉,我前面的说法有问题。是这样的,同一端口号只能被一个进程使用。
两边的UDPPORT要定义成同样的值,
但在Client端,要把
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
addr.sin_port := htons(UDPPORT);
if Bind(s, addr, sizeof(addr)) <> 0 then
begin
showmessage('bind fail');
end;
去掉。

 
另外Server端要写FSockAddrIn.SIn_Port := htons(UDPPORT);

顺便说一下,我不是专业的,是很菜的。只是由于最近比较空闲,天天泡在这儿,勤于回答
问题(我一般喜欢回答简单问题),所以得了这一点点分数。但是你向别人请教时态度要谦虚,
毕竟大家都是在互相帮助,是纯粹义务劳动。年轻气盛可以理解,但是尊重他人是一个基本
的素质。
 
其实我是很谦虚的,只不过看不惯有些人老是当批评家,我不喜欢批评家,我喜欢实干家!
就象ZW84611这样子的!
 
实干家应该是埋头于书本当中,多思考为什么,多看相关的书,不是畏难不肯下苦工夫学
多写代码,,,不是碰到什么问题就问。。。。。。。。。。[:(]
 
后退
顶部