《标准TCPIP编程接口—Socket.ppt》由会员分享,可在线阅读,更多相关《标准TCPIP编程接口—Socket.ppt(101页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、标准标准TCPIP编程接口编程接口Socket第17章 标准TCP/IP编程接口 Socket第17章 标准TCP/IP编程接口 Socket 17.1 套接口概述17.2 地址与地址操作函数17.2.1 INET协议族地址结构sockaddr_in17.2.2 IPv4地址结构in_addr17.2.3 通用地址结构sockaddr17.2.4 地址操作函数17.3 端口17.4 字节序问题17.5 三种套接口类型和两种I/O模式17.5.1 套接口的类型17.5.2 I/O模式第17章 标准TCP/IP编程接口Socket17.6 基本套接口函数 17.7 简单的客户端程序17.6.1 W
2、SAStartup 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 conect17.6.7 recv和send17.6.8 recvfrom和sendto17.6.9 closesocket17.6.10 WSACleanup17.1 套接口概述Berkeley sockets 接口在windows平台上的移植版本称为Winsock。最初的伯克利套接口API在windows平台上的移植版本是Winsock1.1,在它的基础上,微软又进一步提供了Winsock2.0从用户的
3、角度来看,套接口是网络通信端点的一种抽象概念,为用户提供一种发送和接收数据的机制。是一种进程间通信的机制,适用于分布式环境。17.2.1 INET协议地址结构sockaddr_in struct sockaddr_inShort sin_family;U_short sin_port;Struct in_addr sin_addr;Char sin_zero8;地址族,一般填AF_INET16位IP端口32位IP地址8个字节的0填充,给结构体初始化清0的函数如下Void*memset(void*dest,int c,size_t count);所以是TCP/IP17.2.2 IPv4地址结构i
4、n_addr struct in_addrUnionstructu_char s_b1,s_b2,s_b3,s_b4;s_un_b;structu_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 sockaddru_short sa_family;char sa_data14;一种是只为TCP/IP,另外是为了提供通用接口以服务多种网
5、络协议开发的通用结构,但要提供足够的信息说明自己的协议,复杂!例如: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
6、_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 addres
7、s 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
8、 Long“(32bit)ntohs()Network to Host Shortntohl()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)l面向连接的TCP数据报套接口(SOCK_DGRAM)l无连接的UDP原始套接口(SOCK_RAW)l可以读写ICMP、IGMP报文,可以用
9、于从IP头起构造自己的报文。17.5.2 I/O模式非阻塞套接字是指执行此套接字的网络调用时,不管是否执行成功,都立即返回。比如调用某个函数读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。17.5.2 I/O模式 简明扼要的来说可以打个比方:你有数个同学来访,有若干数据需要收取:1、你时不时的去门口看看,没有看到你同学的话就回客厅等待,看到同学就接到客厅来,非阻塞模式,无论收到数据与否都返回。2、你一直在门口等着你同学,接到后才回客厅,阻塞模式,接收到数据后才返回。17.5.2 I/O
10、模式阻塞(BLOCK):便于使用非阻塞(NONBLOCK):效率较高默认情况下,Winsock函数都以阻塞模式工作17.6 基本套接口函数 例如:TCP服务器程序流程:初始化Winsock创建一个Socket绑定并监听本地的特定端口accept接收客户端的连接在accept操作返回的Socket上进行数据通信关闭Socket最后结束Winsock的使用17.6 基本套接口函数WSAStartupSocketBindListenAcceptConnectrecv和sendrecvfrom和sendtoClosesocketWSACleanup17.6.1 WSAStartup 简述简述:#inc
11、lude int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);wVersionRequested:应用程序需要的最高版本,双字节数值型,高位字节指出副版本(修正)号,低位字节指明主版本号。lpWSAData:指向WSADATA数据结构的指针,用来接收Windows Sockets实现的信息。17.6.1 WSAStartup 注释注释:WSAStartup()函数必须是应用程序或DLL调用的第一个Winsock函数。成功调用之后才能进一步的调用别的Winsock函数。它允许应用程序或DLL指明Windows Sockets AP
12、I的版本号及获得特定Windows Sockets实现的细节。17.6.1 WSAStartup 注释注释:WSAStartup()的调用过程l一方面是初始化ws2_32.dll。l另一方面和Winsock库进行版本协商,只有要求的版本=系统支持的最低版本(下限)才成功。并且在wHighVersion中返回系统支持的最高版本,在wVersion中返回系统支持的高版本(上限)和wVersionRequested中的较小者。然后Winsock库就会假设应用程序将使用wVersion。如果WSDATA结构中的wVersion域对调用方来说不可接收,要么去另一个Windows Sockets DLL中
13、搜索,要么初始化失败。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
14、1.1 1.1 1.1 1.1 use 1.11.0 1.11.0 1.11.01.0use 1.0 1.01.0 1.11.01.01.1use 1.01.1 1.0.1.1 1.11.1 1.1use 1.11.11.01.1 1.01.0失败1.0 1.11.0WSAVERNOTSUPPORTED1.0 1.11.0 1.11.11.11.1use 1.11.1.2.01.12.01.11.1use 1.12.01.12.0 1.1 1.1失败17.6.1 WSAStartup 返回值返回值:0:成功 否则返回错误代码 注意通常依靠应用程序调用WSAGetLastError()机制获得的
15、错误代码可能不完全,因为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
16、 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
17、 socket(int af,int type,int protocol);返回值:返回值:非负整数描述符表示成功,-1表示出错AfAf指定协议族,一般设为AF_INET,对应internet。Type有三种类型ProtocolProtocol指定所用的协议,在TCP或UDP编程的时候都取0。类型(type)SOCK_STREAMSOCK_DGRAMSOCK_RAM解释字节流套接口数据报套接口原始套接口af=AF_INET时选择的协议TCPUDPIPv417.6.2 socket示例:SOCKET sock=socket(AF_INET,SOCK_STREAM,0);SOCKET sock=s
18、ocket(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函数,系统会在通信前自动选择一个本地地址(10245000)。但服务进
19、程则必须绑定到一个为客户端所知的地址上。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()创建套接口后,它便存在于一个名字
20、空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。17.6.3 bind注释:注释:在Internet地址族中,一个名字包括几个组成部分,对于SOCK_DGREAM和SOCK_STREAM类套接口,名字由三部分组成:主机地址,协议号(显式设置为UDP和TCP)和用以区分应用的端口号。如果一个应用并不关心分配给它的地址,则可将Internet地址设置为INADDR_ANY,或将端口号置为0。如果Internet地址段为INADDR_ANY,则可使用任意网络接口;在有多种主机环境下可简化编程。如果端口号置为0,则WIND
21、OWS套接口实现将给应用程序分配一个值在1024到5000之间的唯一的端口。应用程序可在bind()后用getsockname()来获知所分配的地址,但必需注意的是,getsockname()只有在套接口连接成功后才会填写Internet地址,这是由于在多种主机环境下若干种Internet地址都是有效的。17.6.3 bind 返回值:返回值:如无错误发生,则bind()返回0。否则的话,将返回SOCKET_ERROR,应用程序可通过WSAGetLastError()获取相应错误代码。17.6.3 bind错误代码:错误代码:WSANOTINITIALISED:在使用此API之前应首先成功地调
22、用WSAStartup()。WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。WSAEADDRINUSE:所定端口已在使用中(参见setoption()中的SO_REUSEADDR选项)。17.6.3 bind错误代码:错误代码:WSAEFAULT:namelen参数太小(小于sockaddr结构的大小)。WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。WSAEAFNOSUPPORT:本协议不支持所指定的地址族。WSAEINVAL:该套接口已与一个地址捆绑。WSAENOBUFS:无足够可用缓冲区,连接过多。WSAENOTSOCK:描述字不是一个套
23、接口。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(
24、“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)/*
25、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()创建一个套接口
26、,再用listen()为申请进入的连接建立一个后备日志,然后便可用accept()接受连接了。listen()仅适用于支持连接的套接口,如SOCK_STREAM类型的。套接口s处于一种“变动”模式,申请进入的连接请求被确认,并排队等待被接受。这个函数特别适用于同时有多个连接请求的服务器;如果当一个连接请求到来时,队列已满,那么客户将收到一个WSAECONNREFUSED错误。17.6.4 listen注释注释:当没有可用的描述字时,listen()函数仍试图正常地工作。它仍接受请求直至队列变空。当有可用描述字时,后续的一次listen()或accept()调用会将队列按照当前或最近的“后备日志
27、”重新填充,如有可能的话,将恢复监听申请进入的连接请求。17.6.4 listen返回值:返回值:如无错误发生,listen()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。17.6.4 listen 错误代码:错误代码:WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。WSAEADDRINUSE:试图用listen()去监听一个在使用中的地址。WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用
28、正在运行中。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:套接口描述字,该套接口在list
29、en()后监听连接。addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。addr参数的实际格式由套接口创建时所产生的地址族确定。addrlen:(可选)指针,指向存有addr地址长度的整形数。17.6.5 accept 注释:注释:本函数从s的等待连接队列中抽取第一个连接,创建一个与s同类的新的套接口并返回句柄。如果队列中无等待连接,且套接口为非阻塞方式,则accept()阻塞调用进程直至新的连接出现。如果套接口为非阻塞方式且队列中等待连接,则accept()返回一错误代码。已接受连接的套接口不能用于接受新的连接,原套接口仍保持开放。17.6.5 accept 注释:注
30、释:addr参数为一个返回参数,其中填写的是为通讯层所知的连接实体地址。addr参数的实际格式由通讯时产生的地址族确定。addrlen参数也是一个返回参数,在调用时初始化为addr所指的地址空间;在调用结束时它包含了实际返回的地址的长度(用字节数表示)。该函数与SOCK_STREAM类型的面向连接的套接口一起使用。如果addr与addrlen中有一个为零NULL,将不返回所接受的套接口远程地址的任何信息。17.6.5 accept返回值:返回值:如果没有错误产生,则accept()返回一个描述所接受包的SOCKET类型的值。否则的话,返回INVALID_SOCKET错误,应用程序可通过调用WS
31、AGetLastError()来获得特定的错误代码。addrlen所指的整形数初始时包含addr所指地址空间的大小,在返回时它包含实际返回地址的字节长度。17.6.5 accept 错误代码:错误代码:WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。WSAEFAULT:addrlen参数太小(小于socket结构的大小)。WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。WSAEINPROGRESS:一个阻塞的WINDOWS套接口
32、调用正在运行中。WSAEINVAL:在accept()前未激活listen()。WSAEMFILE:调用accept()时队列为空,无可用的描述字。WSAENOBUFS:无可用缓冲区空间。WSAENOTSOCK:描述字不是一个套接口。WSAEOPNOTSUPP:该套接口类型不支持面向连接服务。WSAEWOULDBLOCK:该套接口为非阻塞方式且无连接可供接受。17.6.5 accept下面是一个调用accept的例子:struct sockaddr_in ServerSocketAddr;int addrlen;addrlen=sizeof(ServerSocketAddr);ServerSo
33、cket=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参数指定一个未连接的数据报或流类套接口。如套接口未被捆绑,则系统赋给本地关联一个唯一的值,且设置套接口为已捆绑
34、。对于流类套接口(SOCK_STREAM类型),函数会引起三次TCP握手,一旦套接口调用成功返回,它就能收发数据了。对于数据报类套接口(SOCK_DGRAM类型),则设置成一个缺省的目的地址,并用它来进行后续的send()与recv()调用。17.6.6 connect 返回值:返回值:若无错误发生,则connect()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。对阻塞套接口而言,若返回值为SOCKET_ERROR则应用程序调用WSAGetLsatError()。如果它指出错误代码为WSAEWOULDBLOCK,则应用程
35、序可以:1.用select(),通过检查套接口是否可写,来确定连接请求是否完成。2.如果您的应用程序使用基于消息的WSAAsynSelect()来表示对连接事件的兴趣,则当连接操作完成后,您会收到一个FD_CONNECT消息。17.6.6 connect错误代码错误代码:WSAENOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。WSAEADDRINUSE:所指的地址已在使用中。WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。WSAEIN
36、PROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。WSAEADDRNOTAVAIL:在本地机器上找不到所指的地址。WSAENOTSUPPORT:所指族中地址无法与本套接口一起使用。WSAECONNREFUSED:连接尝试被强制拒绝。WSAEDESTADDREQ:需要目的地址。17.6.6 connect错误代码错误代码:WSAEFAULT:namelen参数不正确。WSAEINVAL:套接口没有准备好与一地址捆绑。WSAEISCONN:套接口早已连接。WSAEMFILE:无多余文件描述字。WSAENETUNREACH:当前无法从本主机访问网络。WSAENOBUFS:无可用缓冲区。
37、套接口未被连接。WSAENOTSOCK:描述字不是一个套接口。WSAETIMEOUT:超时时间到。WSAEWOULDBLOCK:套接口设置为非阻塞方式且连接不能立即建立。可用select()调用对套接口写,因为select()时会进行连接。17.6.6 connect下面是一个例子:struct sockaddr_in daddr;memset(void*)&daddr,0,sizeof(daddr);daddr.sin_family=AF_INET;daddr.sin_port=htons(8888);daddr.sin_addr.s_addr=inet_addr(133.197.22.4)
38、;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和s
39、end(recv)注释:注释:本函数用于已连接的数据报或流式套接口s进行数据的接收。对SOCK_STREAM类型的套接口来说,本函数将返回所有可用的信息,最大可达缓冲区的大小。如果套接口被设置为线内接收带外数据(选项为SO_OOBINLINE),且有带外数据未读入,则返回带外数据。应用程序可通过调用ioctlsocket()的SOCATMARK命令来确定是否有带外数据待读入。17.6.7 recv和send(recv)注释:注释:对于数据报类套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且rec
40、v()函数返回WSAEMSGSIZE错误。如果没有数据待读,那么除非是非阻塞模式,不然的话套接口将一直等待数据的到来,此时将返回SOCKET_ERROR错误,错误代码是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以获知何时数据到达。17.6.7 recv和send(recv)如果套接口为SOCK_STREAM类型,并且远端“正常”地中止了连接,那么recv()一个数据也不读取,立即返回。如果被“强制”中止,那么recv()将以WSAECONNRESET错误失败返回。在套接口的所设选项之上,还可用标志位flag来影响函数的执行方式。也就是说,本函数的语义既取
41、决于套接口选项,也取决于标志位参数。标志位可取下列值:值意义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:WINDO
42、WS套接口实现检测到网络子系统失效。WSAENOTCONN:套接口未连接。WSAEINTR:阻塞进程被WSACancelBlockingCall()取消。WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。WSAENOTSOCK:描述字不是一个套接口。WSAEOPNOTSUPP:指定了MSG_OOB,但套接口不是SOCK_STREAM类型的。WSAESHUTDOWN:套接口已被关闭。当一个套接口以0或2的how参数调用shutdown()关闭后,无法再用recv()接收数据。17.6.7 recv和send(recv)错误代码:错误代码:WSAEWOULDBLOCK:套
43、接口标识为非阻塞模式,但接收操作会产生阻塞。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:
44、调用执行方式。17.6.7 recv和send(send)注释:注释:send()适用于已连接的数据报或流式套接口发送数据。对于数据报类套接口,必需注意发送数据长度不应超过通讯子网的IP包最大长度。IP包最大长度在WSAStartup()调用返回的WSAData的iMaxUdpDg元素中。如果数据太长无法自动通过下层协议,则返回WSAEMSGSIZE错误,数据不会被发送。17.6.7 recv和send(send)注释:注释:请注意成功地完成send()调用并不意味着数据传送到达。如果传送系统的缓冲区空间不够保存需传送的数据,除非套接口处于非阻塞I/O方式,否则send()将阻塞。对于非阻塞S
45、OCK_STREAM类型的套接口,实际写的数据数目可能在1到所需大小之间,其值取决于本地和远端主机的缓冲区大小。可用select()调用来确定何时能够进一步发送数据。17.6.7 recv和send(send)在相关套接口的选项之上,还可通过标志位flag来影响函数的执行方式。也就是说,本函数的语义既取决于套接口的选项也取决于标志位。后者由以下一些值组成:值意义MSG_DONTROUTE 指明数据不选径。一个WINDOWS套接口供应商可以忽略此标志 MSG_OOB 发送带外数据(仅适用于SO_STREAM;)17.6.7 recv和send(send)返回值:返回值:若无错误发生,send()
46、返回所发送数据的总数(请注意这个数字可能小于len中所规定的大小)。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。17.6.7 recv和send(send)错误代码:错误代码:WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。WSAEACESS:要求地址为广播地址,但相关标志未能正确设置。WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。WSAEINPROGRESS:
47、一个阻塞的WINDOWS套接口调用正在运行中。WSAEFAULT:buf参数不在用户地址空间中的有效位置。WSAENETRESET:由于WINDOWS套接口实现放弃了连接,故该连接必需被复位。WSAENOBUFS:WINDOWS套接口实现报告一个缓冲区死锁。WSAENOTCONN:套接口未被连接。WSAENOTSOCK:描述字不是一个套接口。17.6.7 recv和send(send)错误代码:错误代码:WSAEOPNOTSUPP:已设置了MSG_OOB,但套接口非SOCK_STREAM类型。WSAESHUTDOWN:套接口已被关闭。一个套接口以1或2的how参数调用shutdown()关闭后
48、,无法再用sned()函数。WSAEWOULDBLOCK:WSAEMSGSIZE:套接口为SOCK_DGRAM类型,且数据报大于WINDOWS套接口实现所支持的最大值。WSAEINVAL:套接口未用bind()捆绑。WSAECONNABORTED:由于超时或其他原因引起虚电路的中断。WSAECONNRESET:虚电路被远端复位。17.6.7 recvfrom和sendto简述简述:recevfrom/sendto类似于recev/send,一般情况下前者用于UDP,后者用于TCP。两者参数完全相同。recevfrom与recev差别是前者在获取数据的同时还可以获得该数据的原地址。UDPTCP1
49、7.6.7 recvfrom和sendto(recvfrom)简述简述:接收一个数据报并保存源地址。#include int recvfrom(SOCKET s,char FAR*buf,int len,int flags,struct sockaddr FAR*from,int FAR*fromlen);s:标识一个已连接套接口的描述字。buf:接收数据缓冲区。len:缓冲区长度。flags:调用操作方式。from:(可选)指针,指向装有源地址的缓冲区。fromlen:(可选)指针,指向from缓冲区长度值。17.6.7 recvfrom和sendto(recvfrom)注释注释:本函数由于
50、从(已连接)套接口上接收数据,并捕获数据发送源的地址。对于SOCK_STREAM类型的套接口,最多可接收缓冲区大小个数据。如果套接口被设置为线内接收带外数据(选项为SO_OOBINLINE),且有带外数据未读入,则返回带外数据。应用程序可通过调用ioctlsocket()的SOCATMARK命令来确定是否有带外数据待读入。对于SOCK_STREAM类型套接口,忽略from和fromlen参数。17.6.7 recvfrom和sendto(recvfrom)注释注释:对于数据报类套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面