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

  • 主题发起人 主题发起人 cfjjj
  • 开始时间 开始时间
呵呵,无忌言之有理
 
我修正了一下:
两边的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的端口应该是一个固定的值,因为Client实现要知道Server的端口和IP才能
通信。而Client的发送端口可以是任意值。
 
ZW84611
我试了一下,是在两台机器上试的,还是不对。我想这里面恐怕还是有点问题。
你原来的程序在发消息时服务器的IP是用户自己填上的,收则是收任何地方来
的,也就是说是先发后收。现在改成两部分后,客户端还是先发后收,但服务
器端是先收后发了。这就存在一个问题,服务器要知道是谁给它发过来的,然后
再将日期时间给这个特定的客户端发过去。我看这里写的服务器端就存在这个
问题,发消息不知发给了谁!
 
server可以通过recvfrom获得Client的地址,但如果你要实现两边都能发送和接受数据,必须
象我以前那样做。否则Client只能发而Server只能收。

先不管Server的发送问题,

在同一台机器上:
两边的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);
之后是否可以通信?
 
其实在同一台机器里应该是可以实现客、服同时运行的。我花了5分钟时间用indy的控件做
了客户端和服务器,在同一台机器上运行效果奇好!既然人家能做的出来,肯定也是用
socket,咱也应该能做的出来啊。不过,我看了一下indy的源码,发现它又用了其他的indy
的控件,一环套一环,我追不下去了!这样简单的socket编程应该不会太难的吧!在JAVA
里,网络上到处都有Datetime和echo的标准例程,用C++的就少了一点,C#的微软的帮助里
就有。找了半天,惟独没有DELPHI的。不知是borland不屑于做,还是什么其他原因。不过
看来新手学DELPHI真不是一件快乐的事。即使象我这样用DELPHI做过一些程序的人,在进入
一个新领域(相对自己而言)也是一愁莫展!
 
to cfjjj:请看一下我上面的话。
 
按照ZW84611所说,又试了一遍,还是不行,一点反应也没有。很显然,服务器并没收到数据
也没有发送数据。关键还是在服务器端的代码有问题!
 
呵呵,开始热闹了。
ZW84611说的对,这里是大家学习的地方,所以我对我说的话表示道歉,sorry!

其它我说这个代码不行也是有道理的,因为我一看client端还有bind,我就觉得应该是对
socket了解不够了。

对于client和server,在同一台机肯定是可以运行的,上面的代码不允许是因为client
端也调用了bind了,系统只能对一个端口(port)bind一次。

我在unix下写socket程序2年多了,曾经遇到的问题和积累的经验还是不少了,大家可以
多多交流,共同进步。
 
to chenxz: 我程序的原意不是那样的,我的Client和Server做在一块儿。cfjjj把它改成两个
了,却没有改对。我已经在上面让他把Client的bind去掉了,只是不知他做了没有。
 
to zw84611
我已经按照您的意思改了,结果还是不行。我觉得应该还是服务器端有问题,一个响应
客户端的请求,另一方面是要知道客户端的IP和端口。我认为和bind()没什么关系,因
为在UDP中应该没有什么服务器和客户端的区别,这里硬要分出客户端和服务器实际上是
业务层的概念。不知我说的对不对!
另外,大家也都有DELPHI吧,能不能在回答问题之前先调试一下。
非常感谢大家的帮助!我觉得现在已经不是我做作业的问题了,因为我用C#已经做完了,
完全可以交差了,现在应该也可以算是一个学术讨论了吧!嘿嘿!!
 
UDP不分服务器和客户端,只要知道对方的端口和IP就可以通讯了,哪个IP发过来的
包,通过RecvFrom返回的TSocketaddr结构中的对方IP和端口发送数据回去就OK了,
那有上面说的那么多的问题。
 
UDP是无连接的,比较简单,Client和Server可以在一起实现。但并不是说UDP就没有Client
和Server,你完全可以把Client和Server分开。如果你学过Comer的"Internetworkin with TCP/IP"
可以看一下其中的"Client-Server Model Of Interaction"一章。

仅实现Client的功能,是不需要bind的。如果在两个机器上运行,Client的bind也不会有问题。但
你前面说了,你要在一台机器上同时运行Client和Server两个程序,所以要把bind去掉,否则
两个程序绑定同一端口,自然要出错。如果你从事Socket,这些都是基本的知识。另外建议
你看一下纯C写的Socket API编程,而且最好是Client和Server分开实现的,对你这方面的学习会有帮助,
C#是比较时髦,但它会让你看不到底层的东西。谈不上学术讨论,一点经验交流而已。

 
服务器端需要绑定端口来完成监听并建立连接
而客户端会有操作系统自动分配端口的
 
Client和Server对于TCP来说才有意义,对于UDP来说没什么意义,
不管是Client和Server都可以绑定到一个本地端口进行接受到发到
这个端口来的所有的UDP包,两个你们说的Server之间也可以通讯
根本没有必要进行区分,很多人区分UDP的S/C只是仿造TCP的说法,
我认为完全没有必要。
 
而TCP就不一样了,他在一个端口上可以和任何发送连接请求的机器建立一个稳定的连接
提供服务,一个端口服务N台机器,所有可以说是Server,一个TCP的Client只能和一台机
器上的Server进行通讯,所有可以分出C/S,
而UDP一个'Client'可以同时和几台机器上的'Server'通讯,所以没有必要区分C/S。
 
udp也可以调用connect来和远程机器连接,连接以后他如果不再次调用connect就只能
和这台机器通讯,这种状态下可以说他是Client,但是这中状态他可以通过再次调用
connect和其他机器连接改变他的远程连接的Server,所以这种状态和TCP的完全不同,
TCP需要关闭原有连接,所以我认为他的这种状态不能说是CLIENT
 
to 张无忌:
你说得都对,我也认为UDP不需要做成Client和Server,做一个就可以了。但我说的C/S
是一种交互模型。发信者为Client,收信者为Server。

另外在实现上,也是可以把C/S分开的。

/* udpExample.h - header used by both UDP server and client examples */

#define SERVER_PORT_NUM 5002 /* server's port number for bind() */
#define REQUEST_MSG_SIZE 1024 /* max size of request message */

/* structure used for client's request */

struct request
{
int display; /* TRUE = display message */
char message[REQUEST_MSG_SIZE]; /* message buffer */
};

--------------------------------------------------------------------------------

/* udpClient.c - UDP client example */

/*
DESCRIPTION
This file contains the client-side of the VxWorks UDP example code.
The example code demonstrates the useage of several BSD 4.4-style
socket routine calls.
*/


/* includes */

#include "vxWorks.h"
#include "sockLib.h"
#include "inetLib.h"
#include "stdioLib.h"
#include "strLib.h"
#include "hostLib.h"
#include "ioLib.h"
#include "udpExample.h"

/****************************************************************************
*
* udpClient - send a message to a server over a UDP socket
*
* This routine sends a user-provided message to a server over a UDP socket.
* Optionally, this routine can request that the server display the message.
* This routine may be invoked as follows:
* -> udpClient "remoteSystem"
* Message to send:
* Greetings from UDP client
* Would you like server to display your message (Y or N):
* y
* value = 0 = 0x0
*
* RETURNS: OK, or ERROR if the message could not be sent to the server.
*/

STATUS udpClient
(
char * serverName /* name or IP address of server */
)
{
struct request myRequest; /* request to send to server */
struct sockaddr_in serverAddr; /* server's socket address */
char display; /* if TRUE, server prints message */
int sockAddrSize; /* size of socket address structure */
int sFd; /* socket file descriptor */
int mlen; /* length of message */

/* create client's socket */

if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR)
{
perror ("socket");
return (ERROR);
}

/* bind not required - port number is dynamic */

/* build server socket address */

sockAddrSize = sizeof (struct sockaddr_in);
bzero ((char *) &serverAddr, sockAddrSize);
serverAddr.sa_len = (u_char) sockAddrSize;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons (SERVER_PORT_NUM);

if (((serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) &&
((serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR))
{
perror ("unknown server name");
close (sFd);
return (ERROR);
}

/* build request, prompting user for message */

printf ("Message to send: /n");
mlen = read (STD_IN, myRequest.message, REQUEST_MSG_SIZE);
myRequest.message[mlen - 1] = '/0';

printf ("Would you like the server to display your message (Y or N): /n");
read (STD_IN, &display, 1);
switch (display)
{
case 'y':
case 'Y': myRequest.display = TRUE;
break;
default: myRey = FALSE;
break;
}

/* send request to server */

if (sendto (sFd, (caddr_t) &myRequest, sizeof (myRequest), 0,
(struct sockaddr *) &serverAddr, sockAddrSize) == ERROR)
{
perror ("sendto");
close (sFd);
return (ERROR);
}

close (sFd);
return (OK);
}

--------------------------------------------------------------------------------

/* udpServer.c - UDP server example */

/*
DESCRIPTION
This file contains the server-side of the VxWorks UDP example code.
The example code demonstrates the useage of several BSD 4.4-style
socket routine calls.
*/

/* includes */
#include "vxWorks.h"
#include "sockLib.h"
#include "inetLib.h"
#include "stdioLib.h"
#include "strLib.h"
#include "ioLib.h"
#include "fioLib.h"
#include "udpExample.h"


/*********************************************************************
*
* udpServer - read from UDP socket and display client's message if requested
*
* Example of VxWorks UDP server:
* -> sp udpServer
* task spawned: id = 0x3a1f6c, name = t2
* value = 3809132 = 0x3a1f6c
* -> MESSAGE FROM CLIENT (Internet Address 150.12.0.11, port 1028):
* Greetings from UDP client
*
* RETURNS: Never, or ERROR if a resources could not be allocated.
*/

STATUS udpServer (void)
{
struct sockaddr_in serverAddr; /* server's socket address */
struct sockaddr_in clientAddr; /* client's socket address */
struct request clientRequest; /* request/Message from client */
int sockAddrSize; /* size of socket address structure */
int sFd; /* socket file descriptor */
char inetAddr[INET_ADDR_LEN];
/* buffer for client's inet addr */

/* set up the local address */

sockAddrSize = sizeof (struct sockaddr_in);
bzero ((char *) &serverAddr, sockAddrSize);
serverAddr.sa_len = (u_char) sockAddrSize;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons (SERVER_PORT_NUM);
serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);

/* create a UDP-based socket */

if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR)
{
perror ("socket");
return (ERROR);
}

/* bind socket to local address */

if (bind (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR)
{
perror ("bind");
close (sFd);
return (ERROR);
}

/* read data from a socket and satisfy requests */

FOREVER
{
if (recvfrom (sFd, (char *) &clientRequest, sizeof (clientRequest), 0,
(struct sockaddr *) &clientAddr, &sockAddrSize) == ERROR)
{
perror ("recvfrom");
close (sFd);
return (ERROR);
}

/* if client requested that message be displayed, print it */

if (clientRequest.display)
{
/* convert inet address to dot notation */

inet_ntoa_b (clientAddr.sin_addr, inetAddr);
printf ("MSG FROM CLIENT (Internet Address %s, port %d):/n%s/n",
inetAddr, ntohs (clientAddr.sin_port), clientRequest.message);
}
}
}

 
:)但是,照你的区分标准,现实中,
服务器也要发送数据到客户端把,客户端也要接受数据把?
这么说的话,按你的标准,难到你不觉的现实中没有C/S了[:D]
 
[:)]我的观点是这样的,如果一个主机既可以收,也可以发,并不是说它没有C/S,而是
它既是Client,又是Server。它可以同时充当两个角色,发信时为Client,收信时为Server。
 
那同时一个你的认为是 Client也是同时是Client和Server,这样的话分什么C/S有什么意义?[:D]
 
后退
顶部