资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第17,章 标准,TCP/IP,编程接口,Socket,第17,章 标准,TCP/IP,编程接口,Socket,17.1,套接口概述,17.2,地址与地址操作函数,17.2.1,INET,协议族地址结构,sockaddr,_in17.2.2 IPv4,地址结构,in_,addr,17.2.3,通用地址结构,sockaddr,17.2.4,地址操作函数,17.3,端口,17.4,字节序问题,17.5,三种套接口类型和两种,I/O,模式,17.5.1,套接口的类型,17.5.2,I/O,模式,第17,章 标准,TCP/IP,编程接口,Socket,17.6,基本套接口函数,17.7,简单的客户端程序,17.6.1,WSAStartup,17.7.1 UDP,客户端,17.6.2,socket 17.7.2 TCP,客户端,17.6.3,bind17.6.4 listen.17.6.5 accept17.6.6,conect,17.6.7,recv,和,send17.6.8,recvfrom,和,sendto,17.6.9,closesocket,17.6.10,WSACleanup,17.1,套接口概述,Berkeley sockets,接口在,windows,平台上的移植版本称为,Winsock。,最初的伯克利套接口,API,在,windows,平台上的移植版本是,Winsock1.1,,在它的基础上,微软又进一步提供了,Winsock2.0,从用户的角度来看,套接口是网络通信端点的一种抽象概念,为用户提供一种发送和接收数据的机制。,是一种进程间通信的机制,适用于分布式环境。,17.2.1,INET,协议地址结构,sockaddr,_in,struct,sockaddr,_in,Short sin_family;,U_short,sin_port;,Struct,in_,addr,sin_,addr,;,Char sin_zero8;,;,地址族,一般填,AF_INET,16位,IP,端口,32位,IP,地址,8个字节的0填充,给结构体初始化清0的函数如下,Void*,memset,(void*,dest,int,c,size_t count);,所以是,TCP/IP,17.2.2,IPv4,地址结构,in_,addr,struct,in_,addr,Union,struct,u_char s_b1,s_b2,s_b3,s_b4;s_un_b;,struct,u_short s_w1,s_w2;s_un_w;,u_long s_,addr,;,s_un;,#define,;,如多网,卡,又不关心接口(,INADDR_ANY,的使用,,P184),202.119.9.199,赋值时的不同分段(4、2、1),INET,协议地址结构中的,IP,地址部分,17.2.3,通用地址结构,sockaddr,struct sockaddr,u_short sa_family;,char sa_data14;,;,一种是只为,TCP/IP,,另外是为了提供通用接口以服务多种网络协议开发的,通用结构,,但要提供足够的信息说明自己的协议,复杂!例如:,Int connetct(socket s,const struct,sockaddr,FAR*name,int namelen),对于程序员来说,很少直接使用这种通用地址结构。,连接时不是,struct sockadr,_in*,而是通用地址结构,17.2.4,地址操作函数,3个常用的地址操作函数:,将点分格式的,IPv4,地址字符串转化为,in_,addr,地址结构适用的,32,位整数:,unsigned long,inet,_,addr,(const char FAR*cp);,将,in_,addr,地址值转化为标准的点分,IP,地址字符串:,char FAR*,inet,_,ntoa,(,struct,in_,addr,in);,域名解析功能:,struct,hostent,FAR*,gethostbyname,(const char FAR*name);,注意,:在使用,winsock,函数之前,应用程序必须首先调用,WSAStartup,函数初始化,ws2_32.dll,,而在应用结束后必须调用,WSACleanup,函数关闭。,Hostent,结构,struct hostent,char FAR*,h_name,;/*official name of host*/,char FAR*FAR*,h_aliases,;,/*alias list*/,short,h_,addrtype,;,/*host address type*/,short,h_length,;/*length of address*/,char FAR*FAR*,h_,addr,_list,;/*list of addresses*/,#define,h_,addr,h_addr_list0,/*address,for backward,compat,*/,;,17.3,端口,0,:不使用,11023,:知名端口,10245000,:,可以被任意客户端程序使用,500165535,:为其他服务器程序预留,17.4,字节序问题,字节顺序转换,htons,()Host to Network Short“(16bit),htonl,()Host to Network Long“(32bit),ntohs,()Network to Host Short,ntohl,()Network to Host Long,连接过程是通过一系列状态表示的,这些状态有:,LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT,和,CLOSED。,17.5.1,三种套接口类型,流套接口,(,SOCK_,STREAM,),面向连接的,TCP,数据报套接口,(,SOCK_,DGRAM,),无连接的,UDP,原始套接口,(,SOCK_RAW),可以读写,ICMP、IGMP,报文,可以用于从,IP,头起构造自己的报文。,17.5.2,I/O,模式,非阻塞,套接字是指执行此套接字的网络调用时,不管是否执行成功,都立即返回。比如调用某个函数读取网络缓冲区中数据,不管是否读到数据都,立即返回,,而不会一直挂在此函数调用上。,阻塞,调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。,17.5.2,I/O,模式,简明扼要的来说可以打个比方:你有数个同学来访,有若干数据需要收取:1、你时不时的去门口看看,没有看到你同学的话就回客厅等待,看到同学就接到客厅来,,非阻塞模式,,无论收到数据与否都返回。2、你一直在门口等着你同学,接到后才回客厅,,阻塞模式,,接收到数据后才返回。,17.5.2,I/O,模式,阻塞,(,BLOCK):,便于使用,非阻塞,(,NONBLOCK):,效率较高,默认情况下,,Winsock,函数都以阻塞模式工作,17.6,基本套接口函数,例如:,TCP,服务器程序流程:,初始化,Winsock,创建一个,Socket,绑定并监听本地的特定端口,accept,接收客户端的连接,在,accept,操作返回的,Socket,上,进行数据通信,关闭,Socket,最后结束,Winsock,的,使用,17.6,基本套接口函数,WSAStartup,Socket,Bind,Listen,Accept,Connect,recv,和,send,recvfrom,和,sendto,Closesocket,WSACleanup,17.6.1,WSAStartup,简述,:,#,include,int,WSAStartup,(WORD,wVersionRequested,LPWSADATA,lpWSAData,);,wVersionRequested,:,应用程序需要的最高版本,双字节数值型,高位字节指出副版本,(,修正,)号,低位字节指明主版本号。,lpWSAData,:,指向,WSADATA,数据结构的指针,用来接收,Windows Sockets,实现的,信息,。,17.6.1,WSAStartup,注释,:,WSAStartup,(),函数必须是应用程序或,DLL,调用的第一个,Winsock,函数。成功调用之后才能进一步的调用别的,Winsock,函数。,它允许应用程序或,DLL,指明,Windows Sockets API,的版本号及获得特定,Windows Sockets,实现的细节。,17.6.1,WSAStartup,注释,:,WSAStartup,(),的调用过程,一方面是初始化,ws2_32.,dll,。,另一方面和,Winsock,库进行版本协商,只有要求的版本=系统支持的最低版本(下限)才成功。并且在,wHighVersion,中返回系统支持的最高版本,在,wVersion,中返回系统支持的高版本(上限)和,wVersionRequested,中的较小者。然后,Winsock,库就会假设应用程序将使用,wVersion,。,如果,WSDATA,结构中的,wVersion,域对调用方来说不可接收,要么去另一个,Windows Sockets DLL,中搜索,要么初始化失败。,17.6.1,WSAStartup,本协议允许,Windows Sockets DLL,和,Windows Sockets,应用程序共同支持一定范围的,Windows Sockets,版本。如果版本范围有重叠,应用程序就可以成功地使用,Windows Sockets DLL。,后面的图表给出了,WSAStartup,(),在不同的应用程序和,Windows Sockets DLL,版本中是如何工作的,:,17.6.1,WSAStartup,应用程序版本,DLL,版本,wVersionRequested,程序要求,最高,wVersion,程序要求与系统最低的最小值,wHighVersion,系统最高,最终结果,1.1,1.1,1.1,1.1,1.1,use 1.1,1.0 1.1,1.0,1.1,1.0,1.0,use 1.0,1.0,1.0 1.1,1.0,1.0,1.1,use 1.0,1.1,1.0.1.1,1.1,1.1,1.1,use 1.1,1.1,1.0,1.1,1.0,1.0,失败,1.0,1.1,1.0,WSAVERNOTSUPPORTED,1.0 1.1,1.0 1.1,1.1,1.1,1.1,use 1.1,1.1.2.0,1.1,2.0,1.1,1.1,use 1.1,2.0,1.1,2.0,1.1,1.1,失败,17.6.1,WSAStartup,返回值,:,0:,成功,否则返回错误代码,注意通常依靠应用程序调用,WSAGetLastError,(),机制获得的错误代码可能不完全,因为,Windows Sockets DLL,可能没有建立,“,上一错误,”,信息储存的客户数据区域。,17,.6.1,WSAStartup,错误代码,:,WSASYSNOTREADY,:,指出网络通信依赖的网络子系统还没有准备好。,WSAVERNOTSUPPORTED,:,所需的,Windows Sockets API,的版本未由特定的,Windows Sockets,实现提供。,WSAEINVAL,:,应用程序指出的,Windows Sockets,版本不被该,DLL,支持。,17,.6.1,WSAStartup,示例,:,#,pragma,comment(lib,“,ws2_32.lib,”,),#,include,#,include,Int,main(,int,arge,char*,argv,),WORD,wVersionReq,=MAKEWORD(0,1);/*,希望使用0.1版本*/,WSAData wsaData,;,int,ret=,WSAStartup,(,wVersionReq,&,wsaData,),if(ret!=0),printf,(,“,%dn,ret,”,),return,1;,else,printf,(,“,High:%,xUse,:%xn,”,wsaData,.,wHighVersion,wsaData,.,wVersion,”,);,WSACleantup,();,return 0;,17.6.2 socket,功能,:使用前创建一个新的套接字,定义,:,SOCKET socket(int,af,int type,int protocol);,返回值:,非负整数描述符表示成功,,-1,表示出错,Af,指定协议族,一般设为,AF_INET,,对应,internet。,Type,有三种类型,Protocol,指定所用的协议,,在,TCP,或,UDP,编程的时候都取0。,类型,(,type),SOCK_STREAM,SOCK_DGRAM,SOCK_RAM,解释,字节流套接口,数据报套接口,原始套接口,af,=AF_INET,时,选择的协议,TCP,UDP,IPv4,17.6.2 socket,示例:,SOCKET sock=socket(AF_INET,SOCK_STREAM,0);,SOCKET sock=socket(AF_INET,SOCK_DGREAM,0);,SOCKET sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);,例如:创建套接字(,TCP),不成功就提示,if(socket(AF_INET,SOCK_STREAM,0)0),fprintf(stderr,“socket creating errorn”);,exit(1);,17.6.3 bind,简述:,本函数将一本地的传输层地址与已经创建的套接口联系起来,一般来说,作为客户端程序,不用关心它的本地地址是什么,也就没有必要调用,bind,函数,系统会在通信前自动选择一个本地地址(1024,5000)。,但,服务进程则必须绑定,到一个为客户端所知的地址上。,17.6.3 bind,#,include,int,bind(SOCKET s,const,struct,sockaddr,FAR*name,int,namelen,);,s,:,标识一未捆绑套接口的描述字,name,:,赋予套接口的地址。,sockaddr,结构定义如下:,struct,sockaddr,u_short,sa,_family;,char sa_data14;,;,namelen,:name,名字的长度,17.6.3 bind,注释:,本,函数,适用于未连接的数据报或流类套接口,在,connect(),或,listen(),调用前使用。当用,socket(),创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。,bind(),函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址,/,端口号)。,17.6.3 bind,注释:,在,Internet,地址族中,一个名字包括几个组成部分,对于,SOCK_DGREAM,和,SOCK_STREAM,类套接口,名字由三部分组成:主机地址,协议号(显式设置为,UDP,和,TCP),和用以区分应用的端口号。如果一个应用并不关心分配给它的地址,则可将,Internet,地址设置为,INADDR_ANY,,或将端口号置为,0,。如果,Internet,地址段为,INADDR_ANY,,则可使用任意网络接口;在有多种主机环境下可简化编程。如果端口号置为,0,,则,WINDOWS,套接口实现将给应用程序分配一个值在,1024到5000,之间的唯一的端口。应用程序可在,bind(),后用,getsockname,(),来获知所分配的地址,但必需注意的是,,getsockname,(),只有在套接口连接成功后才会填写,Internet,地址,这是由于在多种主机环境下若干种,Internet,地址都是有效的。,17.6.3 bind,返回值:,如无错误发生,则,bind(),返回,0,。否则的话,将返回,SOCKET_ERROR,,应用程序可通过,WSAGetLastError,(),获取相应错误代码。,17.6.3 bind,错误代码:,WSANOTINITIALISED,:,在使用此,API,之前应首先成功地调用,WSAStartup,()。,WSAENETDOWN,:WINDOWS,套接口实现检测到网络子系统失效。,WSAEADDRINUSE,:,所定端口已在使用中(参见,setoption,(),中的,SO_REUSEADDR,选项)。,17.6.3 bind,错误代码:,WSAEFAULT,:,namelen,参数太小(小于,sockaddr,结构的大小)。,WSAEINPROGRESS,:,一个阻塞的,WINDOWS,套接口调用正在运行中。,WSAEAFNOSUPPORT,:,本协议不支持所指定的地址族。,WSAEINVAL,:,该套接口已与一个地址捆绑。,WSAENOBUFS,:,无足够可用缓冲区,连接过多。,WSAENOTSOCK,:,描述字不是一个套接口。,17.6.3 bind,示例:创建,TCP,绑定,IP,和端口,SOCKET sock=socket(AF_INET,SOCK_STREAM,0);,Struct sockaddr,_in local;,Memset,(&local,0,sizeof,(local);,local.sin_,addr,.s_,addr,=,inet,_,addr,(,“,202.119.9.199,”,);,Local.sin_family=AF_INET;,Local.sin_port=,htons,(9999);,If(bind(sock,(,struct,sockaddr,*)&local,sizeof,(local)=SOCKET_ERROR),Printf,(,“,Error:%dn,”,WSAGetlastError,();,WSACleanup,();,Return,1;,17.6.3 bind,如果一个应用程序需要把端口捆绑到超过,10245000,范围的特定端口时,比如,rsh,需要捆绑到任一保留端口,则可如下编程:,SOCKADDR_IN sin;,SOCKET s;,u_short,alport,=IPPORT_RESERVED;,sin.sin_family=AF_INET;,sin.sin_,addr,.s_,addr,=0;,for(;),sin.sin_port=,htons,(,alport,);,if(bind(s,(LPSOCKADDR)&sin,sizeof,(sin)=0),/*it worked*/,if(,GetLastError,()!=WSAEADDRINUSE),/*fail*/,alport,-;,if(,alport,=IPPORT_RESERVED/2),/*failall unassigned reserved ports are*/,/*in use.*/,17.6.4 listen,简述:,创建一个套接口并监听申请的连接,.,#,include,int,listen(SOCKET s,int,backlog);,S,:,用于标识一个已捆绑未连接套接口的描述字。,backlog,:,等待连接队列的最大长度。,17.6.4 listen,注释,:,为了接受连接,先用,socket(),创建一个套接口,再用,listen(),为申请进入的连接建立一个后备日志,然后便可用,accept(),接受连接了。,listen(),仅适用于支持连接的套接口,如,SOCK_STREAM,类型的。套接口,s,处于一种,“,变动,”,模式,申请进入的连接请求被确认,并排队等待被接受。这个函数特别适用于同时有多个连接请求的服务器;如果当一个连接请求到来时,队列已满,那么客户将收到一个,WSAECONNREFUSED,错误。,17.6.4 listen,注释,:,当没有可用的描述字时,,listen(),函数仍试图正常地工作。它仍接受请求直至队列变空。当有可用描述字时,后续的一次,listen(),或,accept(),调用会将队列按照当前或最近的,“,后备日志,”,重新填充,如有可能的话,将恢复监听申请进入的连接请求。,17.6.4 listen,返回值:,如无错误发生,,listen(),返回,0,。,否则的话,返回,SOCKET_ERROR,错误,应用程序可通过,WSAGetLastError,(),获取相应错误代码。,17.6.4 listen,错误代码:,WSANOTINITIALISED,:,在使用此,API,之前应首先成功地调用,WSAStartup,()。,WSAENETDOWN,:WINDOWS,套接口实现检测到网络子系统失效。,WSAEADDRINUSE,:,试图用,listen(),去监听一个在使用中的地址。,WSAEINPROGRESS,:,一个阻塞的,WINDOWS,套接口调用正在运行中。,WSAEINVAL,:,该套接口未用,bind(),进行捆绑,或已被连接。,17.6.4 listen,错误代码:,WSAEISCONN,:,套接口已被连接。,WSAEMFILE,:,无可用文件描述字。,WSAENOBUFS,:,无可用缓冲区空间。,WSAENOTSOCK,:,描述字不是一个套接口。,WSAEOPNOTSUPP,:,该套接口不正常,listen(),调用。,17.6.5 accept,简述:,在一个套接口接受一个连接。,#,include SOCKET accept(SOCKET s,struct,sockaddr,FAR*,addr,int,FAR*,addrlen,);,s,:,套接口描述字,该套接口在,listen(),后监听连接。,addr,:(,可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。,addr,参数的实际格式由套接口创建时所产生的地址族确定。,addrlen,:(,可选)指针,指向存有,addr,地址长度的整形数。,17.6.5 accept,注释:,本,函数,从,s,的等待连接队列中抽取第一个连接,创建一个与,s,同类的新的套接口并返回句柄。如果队列中无等待连接,且套接口为非阻塞方式,则,accept(),阻塞调用进程直至新的连接出现。,如果套接口为非阻塞方式且队列中等待连接,,则,accept(),返回一错误代码。已接受连接的套接口不能用于接受新的连接,原套接口仍保持开放。,17.6.5 accept,注释:,addr,参数为一个返回参数,其中填写的是为通讯层所知的连接实体地址。,addr,参数的实际格式由通讯时产生的地址族确定,。,addrlen,参数也是一个返回参数,在调用时初始化为,addr,所指的地址空间;在调用结束时它包含了实际返回的地址的长度(用字节数表示)。该函数与,SOCK_STREAM,类型的面向连接的套接口一起使用。,如果,addr,与,addrlen,中有一个为零,NULL,,将不返回所接受的套接口远程地址的任何信息。,17.6.5 accept,返回值:,如果没有错误产生,则,accept(),返回一个描述所接受包的,SOCKET,类型的值。否则的话,返回,INVALID_SOCKET,错误,应用程序可通过调用,WSAGetLastError,(),来获得特定的错误代码。,addrlen,所指的整形数初始时包含,addr,所指地址空间的大小,在返回时它包含实际返回地址的字节长度。,17.6.5 accept,错误代码:,WSANOTINITIALISED,:,在使用此,API,之前应首先成功地调用,WSAStartup,()。,WSAENETDOWN,:WINDOWS,套接口实现检测到网络子系统失效。,WSAEFAULT,:,addrlen,参数太小(小于,socket,结构的大小)。,WSAEINTR,:,通过一个,WSACancelBlockingCall,(),来取消一个(阻塞的)调用。,WSAEINPROGRESS,:,一个阻塞的,WINDOWS,套接口调用正在运行中。,WSAEINVAL,:,在,accept(),前未激活,listen()。,WSAEMFILE,:,调用,accept(),时队列为空,无可用的描述字。,WSAENOBUFS,:,无可用缓冲区空间。,WSAENOTSOCK,:,描述字不是一个套接口。,WSAEOPNOTSUPP,:,该套接口类型不支持面向连接服务。,WSAEWOULDBLOCK,:,该套接口为非阻塞方式且无连接可供接受。,17.6.5 accept,下面是一个调用,accept,的例子:,struct,sockaddr,_in,ServerSocketAddr,;,int,addrlen,;,addrlen,=,sizeof,(,ServerSocketAddr,);,ServerSocket,=accept(,ListenSocket,(,struct,sockaddr,*)&,ServerSocketAddr,&,addrlen,);,17.6.6 connect,简述,:客户端建立与一个服务端的连接。,#,include,int,connect(SOCKET s,const,struct,sockaddr,FAR*name,int,namelen,);,s,:,标识一个未连接套接口的描述字。,name,:,欲进行连接的端口名。,namelen,:,名字长度。,17.6.6 connect,注释:,s,参数指定一个未连接的数据报或流类套接口。如套接口未被捆绑,则系统赋给本地关联一个唯一的值,且设置套接口为已捆绑。,对于流类套接口(,SOCK_STREAM,类型),函数会引起三次,TCP,握手,一旦套接口调用成功返回,它就能收发数据了。,对于数据报类套接口(,SOCK_DGRAM,类型),则设置成一个缺省的目的地址,并用它来进行后续的,send(),与,recv,(),调用。,17.6.6 connect,返回值:,若无错误发生,则,connect(),返回,0,。否则的话,返回,SOCKET_ERROR,错误,应用程序可通过,WSAGetLastError,(),获取相应错误代码。对阻塞套接口而言,若返回值为,SOCKET_ERROR,则应用程序调用,WSAGetLsatError,()。,如果它指出错误代码为,WSAEWOULDBLOCK,,则应用程序可以:,1,.用,select(),,通过检查套接口是否可写,来确定连接请求是否完成。,2.,如果您的应用程序使用基于消息的,WSAAsynSelect,(),来表示对连接事件的兴趣,则当连接操作完成后,您会收到一个,FD_CONNECT,消息。,17.6.6 connect,错误代码,:,WSAENOTINITIALISED,:,在使用此,API,之前应首先成功地调用,WSAStartup,()。,WSAENETDOWN,:WINDOWS,套接口实现检测到网络子系统失效。,WSAEADDRINUSE,:,所指的地址已在使用中。,WSAEINTR,:,通过一个,WSACancelBlockingCall,(),来取消一个(阻塞的)调用。,WSAEINPROGRESS,:,一个阻塞的,WINDOWS,套接口调用正在运行中。,WSAEADDRNOTAVAIL,:,在本地机器上找不到所指的地址。,WSAENOTSUPPORT,:,所指族中地址无法与本套接口一起使用。,WSAECONNREFUSED,:,连接尝试被强制拒绝。,WSAEDESTADDREQ,:,需要目的地址。,17.6.6 connect,错误代码,:,WSAEFAULT,:,namelen,参数不正确。,WSAEINVAL,:,套接口没有准备好与一地址捆绑。,WSAEISCONN,:,套接口早已连接。,WSAEMFILE,:,无多余文件描述字。,WSAENETUNREACH,:,当前无法从本主机访问网络。,WSAENOBUFS,:,无可用缓冲区。套接口未被连接。,WSAENOTSOCK,:,描述字不是一个套接口。,WSAETIMEOUT,:,超时时间到。,WSAEWOULDBLOCK,:,套接口设置为非阻塞方式且连接不能立即建立。可用,select(),调用对套接口写,因为,select(),时会进行连接。,17.6.6 connect,下面是一个例子:,struct,sockaddr,_in,daddr,;,memset,(void*),daddr,.sin_family=AF_INET;,daddr,.sin_port=htons(8888);,daddr,.sin_,addr,.s_,addr,=inet_addr(133.197.22.4);connect(,ClientSocket,(,struct,sockaddr,*)&,daddr,sizeof,(,daddr,);,17.6.7,recv,和,send(,recv,),功能,:从一个套接口接收数据,可以是面向连接的,必须是已经连接的。,也可以是无连接的,但必须是已经绑定的。,17.6.7,recv,和,send(,recv,),简述,:从一个套接口接收数据。,#,include,int,recv,(SOCKET s,char FAR*,buf,int len,int,flags);,s,:,一个标识已连接套接口的描述字。,buf,:,用于接收数据的缓冲区。,len,:,缓冲区长度。,flags,:,指定调用方式。,17.6.7,recv,和,send(,recv,),注释:,本函数用于已连接的数据报或流式套接口,s,进行数据的接收。,对,SOCK_STREAM,类型的套接口来说,本函数将返回所有可用的信息,最大可达缓冲区的大小。如果套接口被设置为线内接收带外数据(选项为,SO_OOBINLINE),,且有带外数据未读入,则返回带外数据。应用程序可通过调用,ioctlsocket,(),的,SOCATMARK,命令来确定是否有带外数据待读入。,17.6.7,recv,和,send(,recv,),注释:,对于数据报类套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且,recv,(),函数返回,WSAEMSGSIZE,错误。如果没有数据待读,那么除非是非阻塞模式,不然的话套接口将一直等待数据的到来,此时将返回,SOCKET_ERROR,错误,错误代码是,WSAEWOULDBLOCK。,用,select(),或,WSAAsynSelect,(),可以获知何时数据到达。,17.6.7,recv,和,send(,recv,),如果套接口为,SOCK_STREAM,类型,并且远端,“,正常,”,地中止了连接,那么,recv,(),一个数据也不读取,立即返回。如果被,“,强制,”,中止,那么,recv,(),将以,WSAECONNRESET,错误失败返回。,在套接口的所设选项之上,还可用标志位,flag,来影响函数的执行方式。也就是说,本函数的语义既取决于套接口选项,也取决于标志位参数。标志位可取下列值:,值,意义,MSG_PEEK,查看当前数据。数据将被复制到缓冲区中,但并不从输入队列中删除。,MSG_OOB,处理带外数据,17.6.7,recv,和,send(,recv,),返回值,:,若无错误发生,,recv,(),返回读入的字节数。如果连接已中止,返回,0,。否则的话,返回,SOCKET_ERROR,错误,应用程序可通过,WSAGetLastError,(),获取相应错误代码。,17.6.7,recv,和,send(,recv,),错误代码:,WSANOTINITIALISED,:,在使用此,API,之前应首先成功地调用,WSAStartup,()。,WSAENETDOWN,:WINDOWS,套接口实现检测到网络子系统失效。,WSAENOTCONN,:,套接口未连接。,WSAEINTR,:,阻塞进程被,WSACancelBlockingCall,(),取消。,WSAEINPROGRESS,:,一个阻塞的,WINDOWS,套接口调用正在运行中。,WSAENOTSOCK,:,描述字不是一个套接口。,WSAEOPNOTSUPP,:,指定了,MSG_OOB,,但套接口不是,SOCK_STREAM,类型的。,WSAESHUTDOWN,:,套接口已被关闭。当一个套接口以,0或2的,how,参数调用,shutdown(),关闭后,无法再用,recv,(),接收数据。,17.6.7,recv,和,send(,recv,),错误代码:,WSAEWOULDBLOCK,:,套接口标识为非阻塞模式,但接收操作会产生阻塞。,WSAEMSGSIZE,:,数据报太大无法全部装入缓冲区,故被剪切。,WSAEINVAL,:,套接口未用,bind(),进行捆绑。,WSAECONNABORTED,:,由于超时或其他原因,虚电路失效。,WSAECONNRESET,:,远端强制中止了虚电路。,17.6.7,recv,和,send(send),简述:,向一个已连接的套接口发送数据。,#,include,int,send(SOCKET s,const char FAR*,buf,int,len,int,flags);,s,:,一个用于标识已连接套接口的描述字。,buf,:,包含待发送数据的缓冲区。,len,:,缓冲区中数据的长度。,flags,:,调用执行方式。,17.6.7,recv,和,send(send),注释:,send(),适用于已连接的数据报或流式套接口发送数据。对于数据报类套接口,必需注意发送数据长度不应超过通讯子网的,IP,包最大长度。,IP,包最大长度在,WSAStartup,(),调用返回,的,WSAData,的,iMaxUdpDg,元素中。如果数据太长无法自动通过下层协议,则返回,WSAEMSGSIZE,错误,数据不会被发送。,17.6.7,recv,和,send(send),注释:,请注意成功地完成,send(),调用并不意味着数据传送到达。,如果传送系统的缓冲区空间不够保存需传送的数据,除非套接口处于非阻塞,I/O,方式,否则,send(),将阻塞。对于非阻塞,SOCK_STREAM,类型的套接口,实际写的数据数目可能,在1,到所需大小之间,其值取决于本地和远端主机的缓冲区大小。可用,select(),调用来确定何时能够进一步发送数据。,17.6.7,recv,和,send(send),在相关套接口的选项之上,还可通过标志位,flag,来影响函数的执行方式。也就是说,本函数的语义既取决于套接口的选项也取决于标志位。后者由以下一些值组成:,值,意义,MSG_DONTROUTE,指明数据不选径。一个,WINDOWS,套接口供应商可以忽略此标志,MSG_OOB,发送带外数据(仅适用于,SO_STREAM;),17.6.7,recv,和,send(send),返回值:,若无错误发生,,send(),返回所发送数据的总数(请注意这个数字可能小于,len,中所规定的大小)。,否则的话,返回,SOCKET_ERROR,错误,应用程序可通过,WSAGetLastError,(),获取相应错误代码。,17.6.7,recv,和,send(send),错误代码:,WSANOTINITIALISED,:,在使用此,API,之前应首先成功地调用,WSAStartup,()。,WSAENETDOWN,:WIND
展开阅读全文