ImageVerifierCode 换一换
格式:DOCX , 页数:13 ,大小:20.84KB ,
资源ID:6521295      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6521295.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(简单的 Winsock 应用程式设计3.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

简单的 Winsock 应用程式设计3.docx

1、简单的 Winsock 应用程式设计3简单的 Winsock 应用程式设计(3) 在前两期的文章中,笔者介绍了如何在 Winsock 环境下建立主从架构的TCP Socket,以及如何利用 Socket 来收送资料;今天,我们接著来看一看如何利用 Winsock 所提供的函式来取得一些基本的网路资料,包括我们本身主机的名称是什麽、系统主动指定给我们的 Socket 的 IP 位址及 port number、我们的Socket 所连接的对方是谁、如何查得某些主机的 IP 位址或名称、以及某些well-known 服务(如 ftp、telnet 等)所用的 port number 是哪一个等等。今

2、天我们使用的展示程式是笔者以前所撰写的一个针对 Winsock 1.1 的 46个函式做测试或教学用的程式,有兴趣了解 46 个函式该如何呼叫的读者,可用anonymous ftp 方式到 .tw 的 UPLOAD/WINKING/JNLIN目录下取得此程式的执行档及原始程式码,档名为 hello.*。读者们也可利用hello 程式来模拟 Server 或 Client 程式,以验证我们所做的动作。【如何知道我们所使用的 local 主机名称】通常我们都会帮我们自己所使用的这台主机设定一个名称;在程式中,我们也可以透过 Winsock 所提供的一个称为 gethostname() 的函式来取得

3、这一个主机名称。 gethostname():获取目前使用者使用的 local host 的名称。格 式: int PASCAL FAR gethostname( char FAR *name, int namelen );参 数: name 用来存放 local host 名称的暂存区namelen name 的大小传回值: 成功 - 0失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)说明: 此函式用来获取 local host 的名称。在程式中我们呼叫的方法如下:gethostname( (char FAR *) hname, sizeof(hn

4、ame) )读者们如果使用过 Trumpet Winsock 的话,可能知道 Trumpet 的环境设定中并没有让我们设定 local host 名称的栏位,所以在执行一些 Public Domain 的Winsock 应用程式(如 ws_ping、wintalk)时,在呼叫 gethostname() 时会产生错误;解决的方法是在 Trumpet 的 hosts 档中加上您的主机 IP 位址及名称,那麽呼叫这个函式时就不会再产生错误了。【如何得知系统主动指定给我们的 IP 位址及 port number】以前的文章中,笔者曾提到 Client 端的 TCP Socket 在呼叫 connec

5、t() 函式去连接 Server 端之前,可以呼叫 bind() 函式来指定 Client 端 Socket 所用的 IP 位址及 port number;但是一般而言,我们 Client 端并不需要呼叫 bind() 来指定特定的 IP 位址及 port number 的,而是交由系统主动帮我们的 Socket 设定 IP 位址及port number (呼叫 connect() 函式时)。但是我们如何得知系统指定了什麽 IP位址及 port number 给我们呢?这就要借助 getsockname() 这个函式了。 getsockname():获取 Socket 的 Local 位址及

6、port number 资料。格式: int PASCAL FAR getsockname( SOCKET s,struct sockaddr FAR *name, int FAR *namelen );参 数: s Socket 的识别码name 存放此 Socket 的 Local 位址的暂存区namelen name 的长度传回值: 成功 - 0失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)说明: 此函式是用来取得已设定位址或已连接之 Socket 的本端位址资料。若是此 Socket 被设定为 INADDR_ANY,则需等真正建立连接成功後

7、才会传回正确的位址。在程式中呼叫的方法为:struct sockaddr_in sa;int salen = sizeof(sa);getsockname( sd, (struct sockaddr FAR *)&sa, &salen )【如何知道和我们的 Socket 连接的对方是谁】连接的 Socket 是有两端的,所以相对於 getsockname() 函式,Winsock 也提供了一个 getpeername() 函式,来让我们获得与我们连接的对方的 IP 位址与 portnumber。 getpeername():获取连接成功之 Socket 的对方 IP 位址及 port numb

8、er。格 式: int PASCAL FAR getpeername( SOCKET s,struct sockaddr FAR *name, int FAR *namelen );参 数: s Socket 的识别码name 储存与此 Socket 连接的对方 IP 位址的暂存区namelen name 的长度传回值: 成功 - 0失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)说明: 此函式可用来取得已连接成功的 Socket 的彼端之位址资料。呼叫的方式如下:struct sockaddr_in sa;int salen = sizeof(sa

9、);getpeername( sd, (struct sockaddr FAR *)&sa, &salen )现在我们仍然利用 WinKing 来当我们的 Winsock Stack,并利用它所提供的工具来观察 Sockets 的连结及资料是否正确。由图 1,我们可以由 WinKing 的视窗看到我们设定这台主机的名称是vincent,IP 位址是 140.92.61.24。我们并利用两个 hello 程式,一个当成 Client (画面右边打开者),一个当成 Server (画面左边最小化者)。Server所用的 port number 是 7016; Client 并没有呼叫 bind()

10、 来指定 portnumber,而是呼叫 connect() 时由系统指定。我们呼叫 gethostname(),得到的答案是 vincent;而 Client 呼叫getsockname() 得到自己的 IP 位址是 140.92.61.24,port number 是 2110(笔者以前曾提过,由系统主动指定的 port number 会介於 1024 到 5000 间);再呼叫 getpeername() 得到与 Client 连接的 Server 端 IP 位址是 140.92.61.24(因为我们的 Client 和 Server 都在同一台主机),port number 是 701

11、6。果然没错!(由 WinKing 的 Sockets Status 视窗亦可观察到相互连接的 Sockets 资料,与我们呼叫函式所得结果相同)(图 1)利用 hello 程式来模拟 Client 和 Server读者必须注意一点,getsockname() 及 getpeername() 所取得的 IP 位址及 portnumber 都是 network byte order,而不是 host byte order;如果您想转成 host byteorder,就必须借助 ntohl() 及 ntohs() 两个函式。而我们能看到 IP 位址以字串方式表达出来,则又是利用了 inet_nto

12、a() 函式;相对地,我们也可利用inet_addr() 函式将字串方式的 IP 位址转换成 in_addr 格式(network byte order 的unsigned long)。 inet_ntoa():将一网路位址转换成点格式字串。格 式: char FAR * PASCAL FAR inet_ntoa( struct in_addr in );参 数: in 一个代表 Internet host 位址的结构传回值: 成功 - 一个代表位址的点格式(dotted) 字串失败 - NULL说明: 此函式将一 Internet 位址转换成a.b.c.d字串格式。 inet_addr():

13、将字串格式的位址转换成 32 位元 in_addr 的格式。格 式: unsigned long PASCAL FAR inet_addr( const char FAR *cp );参 数: cp 一个代表 IP 位址的点格式(dotted) 字串传回值: 成功 - 一个代表 Internet 位址的 unsigned long失败 - INADDR_NONE说明: 此函式将一点格式的位址字串转换成适用之 Intenet 位址。点格式字串可为以下四种方式之任一:(i) a.b.c.d (ii) a.b.c (iii) a.b (iv) a图 1 的 hello 程式中,我们将 Local 资

14、料写到 dispmsg 中,再显示出来;其用法如下:wsprintf(LPSTR)dispmsg, OK! local ip=%s, local port=%d,inet_ntoa(sa.sin_addr), ntohs(sa.sin_port);【Winsock 提供的资料库函式】Winsock 也提供了同步与非同步的网路资料库函式;不过读者们要知道,此处的资料库指的并非如 Informix, Oracle 等商业用途的资料库系统,而是指主机IP 位址及名称、well-known 服务的名称及 Socket 型态及所用的 port number、以及协定(protocol)名称及代码等。【同

15、步资料库函式】首先我们来看一下第一组:gethostbyname() 及 gethostbyaddr() 函式这两个函式的用途是让我们可以由某个主机名称求得它的 IP 位址,或是由它的 IP 位址求得它的名称。一般我们经常会用到的是由名称求得 IP 位址;因为很少人会去记某台机器的 IP 位址的,另外 TCP/IP 封包的 IP header 上也必须记载送、收主机的 IP 位址,而不是主机名称。 gethostbyname():利用某一 host 的名称来获取该 host 的资料。格 式: struct hostent FAR * PASCAL FARgethostbyname( const

16、 char FAR *name );参 数: name host 的名称传回值: 成功 - 指向一个 hostent 结构的指标失败 - NULL (呼叫 WSAGetLastError() 可得知原因)说明: 此函式是利用 host 名称来获取该主机的其他资料,如 host 的位址、别名,位址的型态、长度等。 gethostbyaddr():利用某一 host 的 IP 位址来获取该 host 的资料。格 式: struct hostent FAR * PASCAL FARgethostbyaddr( const char FAR *addr, int len, int type );参 数

17、: addr network 排列方式的位址len addr 的长度type PF_INET(AF_INET)传回值: 成功 - 指向一个 hostent 结构的指标失败 - NULL (呼叫 WSAGetLastError() 可得知原因)说明: 此函式是利用 IP 位址来获取该主机的其他资料,如 host 的名称、别名,位址的型态、长度等。程式中呼叫的方式分别如下:char host_name30;struct hostent far *htptr;/* 假设 host_name 的值已先设定为我们要求得资料的主机名称 */htptr = (struct hostent FAR *) ge

18、thostbyname( (char far *) host_name )struct in_addr host_addr;struct hostent far *htptr;/* 假设 host_addr 的值已先设定为我们要求得资料的主机的network byteorder 方式的 IP 位址*/htptr = (struct hostent FAR *) gethostbyaddr(char far *)&host_addr, 4,PF_INET)一般言,程式中呼叫到 gethostbyname() 及 gethostbyaddr() 时,WinsockStack 会先在 local 的

19、 hosts档中找看看是否有这个主机的资料;如果没有,则可能再透过领域名称服务(Domain Name Service)的功能,向名称伺服器(Name Server)查询;所以呼叫这两个函式时,有时会等一下子才获得答覆。如果您想让程式执行快一些的话,可将常用主机的资料放在 hosts 档中,这样就不必透过 DNS 去查询了。接下来我们来看 getservbyname() 及 getservbyport() 这两个函式。大部份的读者应该都用过 telnet、mail、ftp、news 等服务应用程式;这些应用程式的协定,比如服务名称、伺服器端所用的 port number、以及 Socket 的

20、型态,都是固定的;这些资料,我们就可以利用 getservbyname() 或 getservbyport()来取得,而不必刻意去记颂它们。 getservbyname():依照服务 (service) 名称及通讯协定(tcp/udp)来获取该服务的其他资料。格 式: struct servent * PASCAL FARgetservbyname( const char FAR *name, const char FAR *proto );参 数: name 服务名称proto 通讯协定名称传回值: 成功 - 一指向 servent 结构的指标失败 - NULL (呼叫 WSAGetLast

21、Error() 可得知原因)说明: 利用服务名称及通讯协定来获得该服务的别名、使用的 port 号码等。 getservbyport():依照服务 (service) 的 port 号码及通讯协定(tcp/udp)来获取该服务的其他资料。格 式: struct servent * PASCAL FARgetservbyport( int port, const char FAR *proto );参 数: port 服务的 port 编号proto 通讯协定名称传回值: 成功 - 一指向 servent 结构的指标失败 - NULL (呼叫 WSAGetLastError() 可得知原因)说明

22、: 利用 port 编号及通讯协定来获得该服务的名称、别名等。程式中的使用方法分别为:char serv_name20;char proto10;struct servent far *svptr;/* 假设 serv_name 及 proto 已先设好服务名称及通讯协定 */svptr = (struct servent FAR *)getservbyname( (char far *)serv_name, (char far*)proto )int serv_port;char proto10;struct servent far *svptr;/* 假设 serv_port 及 prot

23、o 已先设好服务所用的 port number 及通讯协定 */svptr = (struct servent FAR *)getservbyport( htons(serv_port), (char far*)proto) )Winsock 环境下,我们能够查询到的服务资料都是存放在 local 的services档中;这个档所存放的都是 well-known 的服务,基本上我们是不需去更改它的。读者也可以将自己提供的服务加到这个档中,不过您所用的服务资料要公诸於世,不然别人的 services 档中可是没有您的服务的资料哟。最後的这组 getprotobyname() 及 getproto

24、bynumber() 函式是用来取得一些协定的资料,比如 tcp、udp、igmp 等。一般而言,我们是不太会用到的。 getprotobyname():依照通讯协定 (protocol) 的名称来获取该通讯协定的其他资料。格 式: struct protoent FAR * PASCAL FARgetprotobyname( const char FAR *name );参 数: name 通讯协定名称传回值: 成功 - 一指向 protoent 结构的指标失败 - NULL (呼叫 WSAGetLastError() 可得知原因)说明: 利用通讯协定的名称来得知该通讯协定的别名、编号等资料

25、。 getprotobynumber():依照通讯协定的编号来获取该通讯协定的其他资料。格 式: struct protoent FAR * PASCAL FARgetprotobynumber( int number );参 数: number 以 host order 排列方式的通讯协定编号传回值: 成功 - 一指向 protoent 结构的指标失败 - NULL (呼叫 WSAGetLastError() 可得知原因)说明: 利用通讯协定的编号来得知该通讯协定的名称、别名等资料。程式中呼叫方式分别如下:struct protoent far *ptptr;char proto_name2

26、0;/* 假设 proto_name 已先设好协定名称 */ptptr = (struct protoent FAR *)getprotobyname( (char far *)proto_name )struct protoent far *ptptr;int proto_num;/* 假设 proto_num 已先设好协定编号 */ptptr = (struct protoent FAR *)getprotobynumber( proto_num )Winsock Stack 对於应用程式呼叫 getprotobyname() 及 getprotobynumber() 的资料,是取自於 l

27、ocal 的protocol档;如无需要,我们也不用去变更这个档案的内容。(图 2)hello 程式呼叫同步资料库函式【非同步资料库函式】Winsock 1.1 针对前面笔者所描述的 6 个同步资料库函式,也提供了相对的6 个非同步资料库函式,它们分别是 WSAAsyncGetHostByName()、WSAAsyncGetHostByAddr()、WSAAsyncGetServByName()、WSAAsyncGetServByPort()、WSAAsyncGetProtoByName()、WSAAsyncGetProtoByNumber()。由於它们取得的资料与同步资料库函式相同,所以笔者

28、仅以WSAAsyncGetHostByName() 为例,说明这些非同步函式,并告诉各位读者,同步和非同步资料库函式不同的地方。由字面来看,非同步的意思就是我们发出问题时,并不会马上得到答覆,而等到系统取到资料时再告知我们。没错,这些非同步资料库函式的作用就是这样。和 WSAAsyncSelect() 函式一样,我们要告诉 Winsock 系统一个接受通知讯息的视窗及讯息代码,以便系统通知我们。我们呼叫同步资料库函式时,return 值是一个指到相对资料的暂存区,而这个资料暂存区是由系统所提供的;但是呼叫非同步资料库函式时,我们必须自己准备资料暂存区,并将此暂存区的位址当成参数,传给系统,以便

29、系统用来储存取到的资料。读者们必须特别注意一点:在系统通知资料取得成功或失败前,千万不可将传给系统的资料暂存区删除释放,不然当系统取得资料要写入时,资料区已不见了,会导至当机的。除此之外,资料暂存区的大小一定要够大,才足够让系统用来存放取得的资料。(Winsock 规格中的建议值是MAXGETHOSTSTRUCT 1024 bytes 大小的暂存区,笔者认为太大了,100 byets差不多就太够了?呼叫非同步资料库函式时,得到的 return 值是一个代码,此代码代表的就是此项呼叫在系统内的编号;由於是非同步,所以我们在得到答案前,仍可呼叫 WSACancelAsyncRequest() 函式

30、来取消原先的呼叫,这个取消的动作就要利用到该代码了。另外,当我们收到结果通知时,wParam 的值也是这个代码;我们此时可以利用 WSAGETASYNCERROR(lParam) 来得知资料取得是成功或失败;如果失败的原因是原先传入的暂存区太小的话,我们亦可利用WSAASYNCGETBUFLEN(lParam) 来得知至少要多大的暂存区才够。 WSAAsyncGetHostByName():利用某一 host 的名称来获取该 host 的资料。(非同步方式)格 式: HANDLE PASCAL FAR WSAAsyncGetHostByName( HWND hWnd,unsigned int wMsg, const char FAR *name, char FAR *buf, intbuflen );参 数: hWnd 动作完成後,接受讯息的视窗 handlewMsg 传回视窗的讯息name host 名称buf 存放 hostent 资料的暂存区buflen buf 的大小传回值: 成功 - 代表此非同步动作的 handle 代码失败 - 0 (呼叫 WSAG

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1