三个网络编程小问题,最关键的是不允许用控件,最好给出源程序!(200分)

C

cfjjj

Unregistered / Unconfirmed
GUEST, unregistred user!
Q1:编写针对DAYTIME服务的UDP客户机和服务器的实现。要求显示DAYTIME返回的日期和时间值。

Q2:编写针对TIME服务的TCP客户机及服务器的实现。要求把TIME服务返回的时间值和接收到应答时客户机的本机时间值相比较,并显示比较结果(包括两值之间的差异)。

Q3:编写单进程多协议的ECHO服务器,使其可以同时为UDP和TCP提供服务。并编制客户机程序对其进行测试。
 
不允许用控件?C or Delphi?
 
delphi就一定要用控件吗?调用API不可以吗?
难道不用控件的程序就一定要用C写吗?
这几道程序其实都是很简单的,如果用控件白痴都会,现在就是要用delphi来深入底层,
既考究咱们编程人员的实力,也考究Delphi的实力!
 
:),我只是不太明白你的意思是仅TCP/UDP实现不用控件还是什么控件都不用,连窗体都
用API写。
另外什么是DAYTIME服务器?

UDP的例子,你稍改一下应该就能满足要求。

unit udp;

interface

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

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

type
Tfrmmain = class(TForm)
Button1: TButton;
Edit1: TEdit;
Memo1: TMemo;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
s: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn;
//利用消息实时获知UDP消息
procedure ReadData(var Message: TMessage);
message WM_SOCK;
public
{ Public declarations }
procedure SendData(Content: String);
end;

var
frmmain: Tfrmmain;

implementation

{$R *.DFM}

procedure Tfrmmain.FormCreate(Sender: TObject);
var
TempWSAData: TWSAData;
//optval: integer;
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);
// exit;
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;
{optval:= 1;
if setsockopt(s,SOL_SOCKET,SO_BROADCAST,pchar(@optval),sizeof(optval)) = SOCKET_ERROR then
begin
showmessage('无法进行UDP广播');
end;}
WSAAsyncSelect(s, frmmain.Handle , WM_SOCK, FD_READ);
//接收端SockAddrIn设定
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(UDPPORT);
label3.Caption := '端口:'+inttostr(UDPPORT);
end;

procedure Tfrmmain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseSocket(s);
end;

procedure Tfrmmain.ReadData(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);
Memo1.Lines.add(value)
end;
end;

procedure Tfrmmain.SendData(Content: String);
var
value{,hostname}: string;
len: integer;
begin

FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(Edit1.text)); //INADDR_BROADCAST; //INADDR_BROADCAST = -1 ?
value := Content;
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 Tfrmmain.Button1Click(Sender: TObject);
begin
senddata(Edit2.text);
end;

end.
 
Socket API
 
zw84611:
你的这个例子不错,不过他是UDP广播。这里面的第一题说的DAYTIME服务器实际上就是监听
收到一个UDP请求后,将服务器的日期和时间发送一个UDP包给客户端,客户端收到这个包后
读出服务器的时间和日期。
你这个例子好象服务器端和客户端是做在一起的,不知是不是?
不让用控件是专指网络部分,而不是窗体和label.
 
》这几道程序其实都是很简单的,如果用控件白痴都会,现在就是要用delphi来深入底层,
》既考究咱们编程人员的实力,也考究Delphi的实力!
我不会用控件,所以我不是白痴。。。。。肯定没实力了,因为我不会api啊。。
我不知道为什么要底层,我只知道在最短的时间内作出最完善的程序来。
你不用控件?那你的窗体用的什么API创建的。你的按钮用的什么api创建的 。
你的文本框用的什么api创建的。。。你是不是一个控件都不用啊。
那你学机器码好了。
嘿嘿。。。。。。。。。。。
 
不是广播,你没看到我把广播的部分注释掉了。服务器端和客户端是做在一起的。
“将服务器的日期和时间发送一个UDP包给客户端”:这很容易做到。


 
To zw84611:
就是不难啊,关键是我没好好学过socket编程,手头上又没有这方面的书,所以上这来请教
大家了。
大师,继续啊!还有第2题和第3题啊!
 
有了第一个解
2,3都是类似的啊?
RFC上对协议写的足够详细了
 
其实你想做的是一个NTP服务和客户端(DAYTIME精度较差)。
所以你首先要定位好你要做的目标,并不是控件与否的问题。如果你需要具体的代码,在GOOGLE.com
上查找一下,肯定有许多的该类现成的项目,而且是用C或C++实现的,没有任何控件。
 
MrMengyi:
大哥,我就是不明白如何建立一个TCP连接啊!是不是只要把connected设成true就行了?
 
好,给你一个用Socket API实现TCP的例子:
{--------------------------------------------------------------
Simple Example.
Implement TCP(both Client and Server) with Socket API
<zw84611@sina.com>
--------------------------------------------------------------}

unit Unit1;

interface

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

const
WM_SOCK = WM_USER + 1; //自定义windows消息
TCP_PORT = 5432; //设定TCP端口号

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
HasConnected, IsServer: boolean;
CliSocket, SvrSocket: integer;
SvrAddrIn, CliAddrIn:TSockAddrIn;
procedure InitSocket;
procedure SendData(Content: string);
procedure ReadData(var Message: TMessage); message WM_SOCK;
procedure SockConnect;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.InitSocket;
var
wsadata: TWsadata;
err{, optval}: integer;
begin

WSAStartup($0101,WSAData);

CliSocket := socket(AF_INET, SOCK_STREAM,IPPROTO_IP);
SvrSocket := socket(AF_INET, SOCK_STREAM,IPPROTO_IP);

if (CliSocket = INVALID_SOCKET)or(SvrSocket = INVALID_SOCKET) then
begin
ShowMessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(CliSocket);
exit;
end;

SvrAddrIn.sin_addr.s_addr:= INADDR_ANY;
SvrAddrIn.sin_family := AF_INET;
SvrAddrIn.sin_port :=htons(TCP_PORT);
Bind(SvrSocket, SvrAddrIn, sizeof(SvrAddrIn));

err := Listen(SvrSocket,5);
if err<>0 then ShowMessage('Listen error.');

{optval := 1;
if SetSockopt(SvrSocket,SOL_SOCKET,SO_REUSEADDR,pchar(@optval),sizeof(optval)) = SOCKET_ERROR then
begin
showmessage('SO_REUSEADDR set error.');
end; }

//绑定消息映射
WSAAsyncSelect(SvrSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE);
WSAAsyncSelect(CliSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE);

end;

procedure TForm1.SockConnect;
var
err: integer;
begin

CliAddrIn.sin_addr.s_addr:=inet_addr(PChar(Edit1.Text));
CliAddrIn.sin_family := AF_INET;
CliAddrIn.sin_port :=htons(TCP_PORT);
repeat
err:=connect(CliSocket,CliAddrIn, SizeOf(CliAddrIn));
if err = -1 then
begin
{ if we use WSAAsyncSelect(CliSocket...) in order to receive data at
Client side, here will get error, but it still works. why?
}
//ShowMessage('connect error.');
//ListBox1.Items.Add('connect error.');
HasConnected := false;
break;
end
else
begin
HasConnected := true;
IsServer := false;
end;
until err=0;

end;

procedure TForm1.SendData(Content: string);
begin
Send(CliSocket,Content[1],length(Content),0);
end;

procedure TForm1.ReadData(var Message: TMessage);
var
Event: word;
Buf:array[0..1023] of char;
AddrLen, DataLen: integer;
begin
//
AddrLen := sizeof(SvrAddrIn);
Event := WSAGetSelectEvent(Message.LParam);

case Event of
FD_CONNECT:
begin
ListBox1.Items.Add('connect');
HasConnected := true;
//do nothing?
end;
FD_ACCEPT:
begin
IsServer := true;
HasConnected := true;
ListBox1.Items.Add('accept');
//CloseSocket(CliSocket);
CliSocket := Accept(SvrSocket,@SvrAddrIn,@AddrLen);
end;
FD_READ:
begin
DataLen := Recv(CliSocket,Buf,1024,0);
buf[DataLen] := #0;
ListBox1.Items.Add(Buf);
end;
FD_WRITE:
begin
ListBox1.Items.Add('write');
end;
FD_OOB:
begin
ListBox1.Items.Add('FD_OOB');
end;
FD_CLOSE:
begin
HasConnected := false;
ListBox1.Items.Add('close');
end;
end; //end of case
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//202.104.32.230
if (not IsServer)and(not HasConnected) then SockConnect;
SendData('hello, world');
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseSocket(SvrSocket);
CloseSocket(CliSocket);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
HasConnected := false;
IsServer := false;
InitSocket;
end;

end.

第3个问题,把1、2合在一起就可以了。
 
>>最关键的是不允许用控件
>>是不是只要把connected设成true就行了?
矛盾啊!

不如看看indy的source了
上面的sock api使用sample对你已经很有用了
(虽然我没仔细看,但标题很明确)
 
zw84611给的例子非常好!过两天结束这个话题时一定给你最高分!
MrMengyi你说的indy是个网站吗,我用GOOGLE没搜到,盼给出地址,我还想更多地了解
winsock api.谢谢!
 
Indy是个网络控件包。D7直接带,D5要自己装。看一下这里:http://www.nevrona.com/Indy/
 
我倒~~~~~~~~~~~~~~~~~~~~~~~~~~!!!!
 
接受答案了.
 
顶部