windowssocket编程实战_第1页
windowssocket编程实战_第2页
windowssocket编程实战_第3页
windowssocket编程实战_第4页
windowssocket编程实战_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、windows socket编程实战Socket中一个比较重要的结构体:hostent,应该用好这个结构体。只允许复制应用程序一个备份,不允许应用程序自己修改,只能由系统修改,在调用任何socket结构之前,都应该copy自己需要的信息。通讯编程详见MSDN中Windows CE document->Application Develop->Communication Services->Windows Sockets章节。1 winsock 的启动和终止WSAStartup():使用winsock之前,必须对其进行初始化(VC中项目创建时不包括socket的时候),将其加载

2、,否则,将返回SOCKET_ERROR错误,错误信息为WSANOTINITIALIZED。用WSAStartup函数可加载WinSock库函数声明:int WSAStartup(WORD wVersionRequested , LPWSADATA lpWSAData);/成功返0,否则返非0参数说明:wVersionRequested : WinSock库的版本号,高位指定副版本,低位指定主版本,可通过MAKEWORD(X , Y )宏指定,X为低位,Y为高位。例:wVersionRequested =MAKEWORD(1,2);lpWSAData :接收WinSock实现细节的LPWSADA

3、TA结构。Typedef struct WSAData    WORD             wVersion;/设置成准备使用的WinSock版本    WORD              wHighVersion;/存放的是现有的WinSock库的最高版本,与wVersionRequested 参数相同 

4、0;  char              szDescriptionWSADESCRIPTION_LEN+1;    char             szSystemStatusWSASYSSTATUS_LEN+1;    unsigned short   iMaxSockets; &

5、#160;  unsigned short   iMaxUdpDg;    char FAR *       lpVendorInfo; WSADATA , FAR* LPWSADATA;则一个程序要使用1.2版本的WinSock,程序为:#include "afxsock.h"WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 2, 2 ); err = WSAS

6、tartup( wVersionRequested, &wsaData );if ( err != 0 ) AfxMessageBox("socket初始化失败!");return;if ( LOBYTE( wsaData.wVersion ) != 2 |HIBYTE( wsaData.wVersion ) != 2 ) WSACleanup( );AfxMessageBox("socket创建版本错误!");return; 各windows平台支持的WinSock最新版本平台WinSock版本Win951.1Win982.2NT4.02.2W

7、in20002.2Win CE1.1使用完WinSock释放所使用的资料:int WSACleanup(void);/成功返回0,否则返回SOCKET_ERROR示例代码:WSACleanup();2创建套接字Socket()和WSASocket()网络通信必须得创建套接字,创建一个套接字,使用下面的函数:SOCKET Socket(int af ,int type,int protocol);或者:SOCKET WSASocket(int af,int type,int protocol,LPWSAPROTOCOL_INFO lpProtocolinfo,GROUP g , DWORD dw

8、Flags)注:WSASocket为Socket的WinSock2版本,其原理与方式与原函数类似。调用成功则返回SOCKET类型的套接字句柄,否则返回INVALID_SOCKET错误参数说明:af:协议簇,是常值,在windows Socket网络程序中,其只能为AF_INET,以下所有内容皆针对于AF_INET协议所言协议簇常值协议簇注释AF_INET网际协议AF_IPXIPX/SPX协议AF_NETBIOSNetBIOS协议AF_APPLETALKAppleTalkAF_TAMATMAF_IRDAInfrared SocketsType :套接字的类型,常值。下列为AFINET协议簇支持的

9、套接字类型:AFINET协议簇支持的套接字类型套接字类型注释所用的通信协议SOCK_STREAM字节流套接字TCP协议SOCK_DGRAM数据报套接字UDP协议SOCK_RAW原始套接字ICMP ,IGMP等协议,此时protocol参数需进行设置例如创建一个TCP套接字:s=Socket(AF_INET , SOCK_STREAM , 0 ) ;3 指定本机地址bind()创建套接字后:服务器端:必须将其绑定到一个已知地址客户端:不必绑定,内核会为其选择地址。Int bind(SOCKET s , const struct sockaddr FAR* name , int namelen)参

10、数说明:s:等待客户进行连接的套接字name:指向struct sockaddr类型的缓冲区的指针,在调用bind前,必须先对其进行填充。内容为本地地址信息。Sockaddr结构体定义:struct sockaddru_short sa_family;charsa_data14;常使用的是另一种结构体类型的Socket地址类型sockaddr_in :struct sockaddr_in short sin_family;/协议簇,必为AF_INET u_short sin_port;/端口号,使用前应用htons函数转换。 struct in_addr sin_addr;/IP地址,使用前应

11、用htonl函数转换 char sin_zero8;namelen:name参数所指的缓冲区的长度,可用sizeof函数取得。使用如下代码为一个已创建的套接字绑定地址:SOCKET s;Struct sockaddr_in localaddr;s=socket(AF_INET,SOCK_STREAM,0);localaddr.sin_family=AF_INET;localaddr.sin_port=htons(5555);localaddr.sin_addr.s_addr=htonl(INADDR_ANY);/自动选取本地地址进行填充bind(s,(SOCKADDR*)&locala

12、ddr,sizeof(localaddr);4建立套接字连接connect()和WSAConnect()函数原型:int connect( SOCKET s, const struct sockaddr FAR *name, int namelen )参数说明:s:上面连接服务器的套接字name:一个指向struct sockaddr 类型的缓冲区的指针,调用connect前,必须对其进行缓冲。namelen:name参数所指的缓冲区的长度,可用sizeof函数取得。WSAConnect()为connect的WinSock2版本:int WSAConnect( SOCKET s, const

13、struct sockaddr FAR *name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS, LPQOS lpGQOS );调用方法与connect类似。使用如下代码与地址为03.03.03.1,端口为5555的TCP服务器建立联系:SOCKET s;struct sockaddr_in remoteaddr;s=socket(AF_INET,SOCK_STREAM,0);remoteaddr.sin_family=AF_INET;remoteaddr.sin_port=htons(555

14、5);remoteaddr.sin_addr.s_addr=inet_addr(“03.03.03.1”);/inet_addr将字符串形式的IP地址转换为正确的IN_ADDR结构的IP地址connect(s,(SOCKADDR*)&remoteaddr,sizeof(remoteaddr);如果成功的与服务器建立连接,connect函数返回0,否则返回SOCKET_ERROR错误.5监听连接listen()指示一个套接字等候进入连接,listen仅仅被TCP服务器调用。当函数Socket创建一个套接字时,它被假设一个主动套接字,即它是一个将调用connect发起连接的客户套接字,函数

15、listen将未连接的套接字转换为被动套接字,指示内核应接收指向此套接字的连接请求。此时套接字将从CLOSED状态转换到LISTEN状态,套接字进入监听模式。函数原型为:int listen( SOCKET s, int backlog );参数说明:s:要监听的已绑定但却没有连接的套接字backlog:内核为此套接字排队的最大连接个数,通过指定backlog值我们可以对同时可处理的连接数进行限制,多于则被丢弃。基层协议本身对backlog有最大限制,如果设定大于它则被用最接近的合法数值代替。调用成功则返回0,不成功则返回SOCKET_ERROR错误。Listen()通常在bind()之后,a

16、ccept之前调用,如下:(省略了错误检测代码)bind(s,(SOCKADDR*)&localaddr,sizeof(localaddr);listen(s,5);accept(.);6 接受连接请求accept()和WSAAccept()accept()函数由TCP服务器调用,它从已完成连接队列头返回下一个已完成连接。在阻塞方式下,如果队列已完成队列为空,则导致进程进入睡眠状态函数原型:SOCKET accept( SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen );SOCKET WSAAccept( SOCKET s,

17、struct sockaddr FAR *addr, LPINT addrlen, LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData );WSAAceept是accept的WinSock2版本。参数说明:s:指定一个处于监听连接状态的套接字addr:指向一个 struct sockaddr类型的缓冲区,用来接收连接方的地,可以置NULL。addlen:整形指针,在调用时它所指的空间存放addr指向的缓冲区长度。在调用返回后,里面是返回的连接方的地址的确切长度。如果我们对客户的身份不想知道,则可将addr和addrlen参数置NULL.例如:

18、newsock=accept(s,NULL,NULL);如果调用成功,则accept返回一个由内核生成的全新的套接字,注意,这个套接字和原来的bind的套接字不为同一个,即,一端至少得两个套接字,一个套接字为windows套接字,由socket创建,负责绑定,监听,一个为C/S间通讯的套接字,代表与客户机的连接,由accept创建,而原来的套接字状态不变,仍处于监听状态,等待客户的连接请求。如果调用失败,则返回一个INVALID_SOCKET的错误。7数据发送send()和sendto()函数原型:int send( SOCKET s, const char FAR *buf, int len

19、, int flags);int sendto( SOCKET s, const char FAR *buf, int len, int flags,const struct sockaddr FAR *to, int tolen);参数描述:s :发送端套接字描述符。Buf:发送数据的缓冲区地址。Len:实际要发送数据的字节数,应小于或者等于套接字s的缓冲区长度,否则报错。Flags:发送数据方式(MSG_DONTROUTE:指定数据不交给路由选择;MSG_OOB:表示要发送带外数据,一般置0)to:接收方sockaddr 结构形式的地址。Tolen:地址结构的长度。说明:send函数并不传

20、送数据,只是协议传的,send只是把buf中的数据copy到s的发送缓冲区的剩余空间里。Copy成功则返回拷贝的实际长度,否则任何错误都返回SOCKET_ERROR错误。注:sendto一般用于数据报(UDP).8 数据接收recv()和recvfrom()recv()用于流套接字,TCP协议。和recvfrom()用于数据报,UDP协议。int recv(SOCKET s, char FAR *buf, int len, int flags );int recvfrom( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr

21、 FAR *from, int FAR fromlen);参数说明:s:接收端套接字描述符。Buf:用来存放接收数据的缓冲区地址。Len:接收数据缓冲区的长度。Flags:处理数据方式(MSG_OOB:读取套接字上的带外数据;MSG_PEEK:查看输入数据,数据将被复制到缓冲区去,但不从输入队列中清除,一般置0)From:recv函数返回的发送方sockaddr 结构形式的地址。fomlen:地址结构的长度。说明:recv把接收缓冲区中的数据copy到buf中,返回实际copy的字节数,任何出错则返回SOCKET_RROR。Recvfom用于数据报协议。9 I/O多路复用Select()指示多

22、个事件中任何一个的发生,并且仅在一个或者多个事件发生或者经过某指定的时间后才唤醒进程。可以检测一个或者多个套接字的状态,满足给定状态的套接字集合由fd_set结构体指示,当select返回时,fd_set结构体被更新,同时select函数返回满足条件的套接字数目。int select( int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);参数说明:nfds:可忽略,系统为兼容性而设readfds,:指向套接字集合,select

23、函数对该集合内的套接字是否可读进行检测。可选参数。Writefds:指向套接字集合,select函数对该集合内的套接字是否可写进行检测。可选参数。Exceptfds:指向套接字集合,select函数对该集合内的套接字是否出错进行检测。可选参数。Timeout: select等待超时的最大时间,timeval 结构类型的结构指针。如果设为NULL,则为阻塞操作。timeval 结构体定义:struct timeval long tv_sec; / seconds long tv_usec; / and microseconds ;fd_set结构体的定义:typedef struct fd_se

24、t u_int fd_count; / how many are SET? SOCKET fd_arrayFD_SETSIZE; / an array of SOCKETs fd_set;常用一组宏定义操作fd_set类型的描述符集合:FD_CLR(s, *set):从集合中删除描述符s;FD_ISSET(s, *set):判断描述符s是否是集合中的一个元素,是则返回非0,不是则返回0;FD_SET(s, *set):增加描述符s到集合中。FD_ZERO(*set):清空集合。10 释放连接closesocket()和shutdown()通讯任务完成后,必须关闭连接以释放套接字句柄的资源。函数

25、原型:int closesocket( SOCKET s );int shutdown( SOCKET s, int how);参数说明:s:要关闭的套接字句柄how:关闭时的操作选择(SD_RECEIVE:表示不再接收数据;SD_SEND:表示不再发送数据;SD_BOTH:表示取消连接两端的收发操作 )说明:1. 函数操作成功则返回0,否则返回SOCKET_ERROR2. closesocket有可能造成数据丢失,因为有可能有几个套接字描述符指向同一个套接字数据结构。套接字数据结构中有一个字段专门存放该结构的被引用次数。当次数为1时系统则清除该结构,大于1时系统仅清除套接字描述符表中对应的表

26、项,并次数递减1。Shutdown则可能做到“从容关闭”,因此尽可能选用shutdown函数。11 其它API函数11.1 getpeername()说明:获得与套接字相连的端地址信息。函数原型:调用成功则int getpeername( SOCKET s, struct sockaddr FAR *name, int FAR *namelen);参数说明:s:标识一已连接的套接字描述符name:接收端地址结构的名字namelen: 一个指向名字结构的指针。注:成功则返回0,否则返回SOCKET_ERROR。11.2 getsockname()说明:获得一个套接字的本地名字。函数原型:int

27、getsockname( SOCKET s, struct sockaddr FAR *name, int FAR *namelen);参数说明:s:标识一已连接的套接字描述符name:接收端地址的名字结构。namelen: 名字缓冲区长度。注:1.成功则返回0,否则返回SOCKET_ERROR。 2.其用于一个已捆绑或者已连接的套接字s,本地址将被返回。当未绑定就connect()时,唯有此函数可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。3>. 若一个套接字与INADDR_ANY捆绑,即该套接字可以用任意主机的地址,此时除非用OnConnect或者a

28、ccept来连接,否则getsockname不会返回主机地址的任何信息,所以INADDR_ANY主要用于多个主机环境中,单主机环境不应该使用此参数。11.3 gethostbyaddr()函数原型:struct HOSTENT FAR * gethostbyaddr( const char FAR *addr, int len, int type )参数说明:addr: 指向网络字节顺序地址的指针。len: 地址的长度,在AF_INET类型地址中为4。type: 地址类型,应为AF_INET。struct HOSTENT结构:struct hostent char FAR * h_name;/

29、正规的主机名字。 char FAR * FAR * h_aliases;/一个以空指针结尾的可选主机名队列。 short h_addrtype;/返回地址的类型:AF_INET。 short h_length;/每个地址的长度(字节数),对AF_INET域为4 char FAR * FAR * h_addr_list;/以空指针结尾的主机地址列表,返回地址以网络顺序排列。;注:gethostbyaddr()函数成功则返回对应于给定地址的包含主机名字和地址信息的hostent结构指针,这个结构由windows socket实现分配,应用程序不应该试图修改或者释放其任何部分,每线程仅有这个结构的拷

30、贝,所以应用程序在发出其它的socket API调用前,应该把自己所需的信息拷贝下来。失败返回空指针。11.4 Gethostbyname()根据名称取得运行代码的机器IP:一个例子:PHOSTENT hostinfo;CString ip;char name255;if(hostinfo = gethostbyname(name) != NULL)ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);11.5文件下载函数:来自于MSDN的web Workshop文档HRESULT URLDownloadToFile( LP

31、UNKNOWN pCaller,/调用者:若为组件,则为组件接口地址,不为组件,则置NULL LPCTSTR szURL,/下载的URL地址,不能置NULL LPCTSTR sz,/下载的文件保存的文件名 DWORD dwReserved,/ 0LPBINDSTATUSCALLBACK lpfnCB/调用者的IBindStatusCallback函数接口地址,可为NULL);12 在程序中显示SOCKET错误信息Ø 程序员自行分配信息缓冲区的方法WSAShowError()TCHAR errMsg2048 = 0;FormatMessage(FORMAT_MESSAGE_FROM_S

32、YSTEM,GetModuleHandle(TEXT("ws2_32.dll"), WSAGetLastError(),NULL,errMsg,sizeof(errMsg)/sizeof(TCHAR),NULL);MessageBox(errMsg, TEXT("ws2_32.dll模块中关于此错误的详细说明:"), MB_ICONERROR);/AfxMessageBox(errMsg);/或者用系统对话框来显示/SetDlgItemText(IDC_STATIC1,errMsg);/或者用静态文本框显示/MessageBox(ghMainWnd, errMsg, TEXT("ws2_32.dll"), MB

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论