第一章:Winsock简介

来源:互联网 发布:兼职软件可靠排行榜 编辑:程序博客网 时间:2024/06/07 22:05

1:Winsock概念

1:Winsock是一种网络编程接口,而不是协议,它支持多种协议

2:使用Winsock需包含winsock2.h和WS2_32.lib

3:WSACleanup()能够释放所有由Winsock分配的资源,并取消进程挂起的Winsock调用,操作系统在退出的时候同样会释放这些资源,但不建议这样做

4:两个错误处理函数:

(1):WSAGetLastError();

(2):WSASetLastError(int);

5:sockaddr_in的sin_family字段需设置为AF_INET,表示使用IP地址族(IPv4)

6:网络上指定IP地址和端口号,必须使用"大端",大端的意义是从最有意义的字节到最无意义的字节方式,这就是网络字节序

7:理解inet_addr,htonl,htons,ntohs,ntohl

 

2:相关API

1:bind(),INADDR_ANY将套接字绑定到系统中所有的接口,以便从这些接口到达的数据都能被套接字接收

2:listen()第二个参数backlog假设为2,当3个客户端同时连接,第三个会返回WSAECONNREFUSED,backlog大小也是有限制的,取决于具体实现,如果传入值超过此限制,系统会用一个最近的合法值代替,没有提供API找出最大backlog

3:接受连接可使用函数accept(),AcceptEx(),WSAAccept();AcceptEx()是accept()的扩展版本,WSAAccept()提供一个函数,通过其返回值来确定是否接受一个连接

4:accept()出错,会返回INVALID_SOCKET,如果将监听套接字设置为异步或非阻塞时,如果没有连接,会返回WSAEWOULDBLOCK

 

1.6.2:TCP状态

进程A调用closesocket()或者shutdown(SD_SEND)时,会发送FIN,对方回复ACK,或者FIN+ACK(也就是三向关闭和四向关闭),此时A发送ACK并需要等待2MSL,此时定义连接的一对套接字都不能被重用,如果试图用此套接字建立连接,会失败并返回WSAEADDRINUSE,可以通过使用套接字选项SO_REFUSEADDR解决,另外,处于2MSL状态的套接字所在的端口,一些实现不允许使用此端口,但Windows可以使用

 

2:相关API(继续)

5:连接通过connect(),WSAConnect(),ConnectEx()实现

6:connect()失败可能错误有:

(1):WSAECONNREFUSED:想连接的计算机没有进程监听相应的端口

(2):WSAETIMEDOUT:试图连接的计算机不可达,原因有到主机之间的路由出现故障或者没有连接互联网等等

7:所有接发数据的函数错误时都返回SOCKET_ERROR,调用WSAGetLastError()有可能返回WSAECONNABORTED和WSAECONNRESET,出现这两种错误的原因是:超时关闭或者对方正在关闭连接

8:send()的flags标志为0是正常发送,MSG_DONTROUTE表示目的主机就在本网络中,无需路由选择,MSG_OOB表示发送的是带外数据,可能的错误有:

(1):WSAECONNABORTED错误,表示在虚拟回路由于超时或者协议错误而中断,此时应该关闭此套接字

(2):WSAECONNRESET:当远程主机进程执行强制关闭或者意外中断重新设置虚拟回路时,或者远程主机重启时,此时也应该关闭套接字

(3):WSAETIMEOUT:连接由于网络故障或者远程主机异常死机而导致连接中断时发生

9:WSASendDisconnect():发送一块数据,然后发送FIN,这和shutdown(SD_SEND)差不多

10:MSG_OOB表示数据是否以带外方式发送,带外发送也就是紧急指针的实现

11:recv():flags标志可以为MSG_PEEK,表示将数据复制到进程缓冲区的同时,不从系统中删除这些数据;MSG_OOB表示接收带外数据

12:在UDP中使用recv()时,如果进程提供的缓冲区小于数据报大小,会返回WSAEMSGSIZE错误,但进程缓冲区会被尽量填满,在TCP中由于是基于流的数据,所以不会碰到此错误

WSARecv()增加了一些新特性,其flags标志可以被设置为MSG_PARTIAL,如果一个协议支持部分消息(如ATM),此标志有2种用法:

(1):调用WSARecv(),当系统发现缓冲区不够时,会设置flags为MSG_PARTIAL,直到数据被接收完

(2):调用时设置MSG_PARTIAL,表示只接收提供的缓冲区那么大的数据,然后就结束

13:WSARecvDisconnect()接收一块数据,并禁止以后再接收数据,效果如果shundown(SD_RECEIVE)一样

 

3:流协议

1:send()一次可能发送不完所有的数据,它会返回实际发送的数据字节数,我们需要设置一个循环来发送剩余的数据

 

4:散播-聚集IO

1:发送的时候发送多个WSABUF,比如发送3个WSABUF,每个表示协议名,长度,具体数据,但实际中一般不用此功能

 

5:中断连接

1:shutdown()

1:此函数可以设置:

(1):SD_RECEIVE:表示上层不能再调用接收函数,它对底层没有影响

(2):SD_SEND:会发送栈上所有的数据,并在收到ACK后,发送FIN

(3):SD_BOTH

2:并非所有面向连接的协议都支持从容关闭,如ATM,他们直接调用closesocket()即可

2:closesocket()

1:用此函数关闭套接字后,再次对此套接字调用函数会返回WSAENOTSOCK错误

2:调用此函数,所有与套接字相关的资源都会被释放,包括队列中的数据

3:调用此函数后,与此套接字相关的调用会返回WSA_OPERATION_ABORTED错误

4:套接字选项SO_LINGER会对此函数行为产生影响

 

6:UDP

1:UDP客户端可以通过connect建立"伪连接",然后使用send,recv收发数据,关闭此"伪连接"的方式是使用INADDR_ANY的地址再次调用connect()

2:对于基于消息的UDP发送数据,可能有两种情况

(1):阻塞发送,数据在被发送完毕之前会形成阻塞

(2):非阻塞发送,如果数据不能完全发送,会返回WSAEWOULDBLOCK,应该稍后再次调用发送函数

3:对于接收

如果接收提供的缓冲不够大,会返回WSAEMSGSIZE错误,UDP会填满缓冲,但会丢弃数据剩余的部分,但如果协议支持部分消息,就可以采用falg为MSG_PARTIAL接收部分消息,支持MSG_PARTIAL的函数只用WSARecvEx

 

7:其他API函数

1:getpeername()获得一个和套接字通信的远端主机地址

2:getsockname(),与getpeername()相反,获得一个套接字本地主机地址

3:WSADuplicateSocket()复制套接字句柄到另外一个进程