Socket 函数说明
1.1 库函数综述
1.1.1 套接字函数
表 1.1 Windows Sockets 1.1 版本Berkeley Sockets函数
函数名说明
accept()确认外来连接,并将它与一个立即建立的数据套接字联系起来。原始套
接字返回到监听状态
bind() 给未命名套接字赋一个本地名
closesocket()从进程对象参考表中删去一个套接字,只有当SO_LINGER设置时才阻塞connect()在指定套接字上初始化连接
getpeername() 获取与指定套接字连接的对等方的名字
getsockname() 获取指定套接字的当前名字
getsockopt() 获取与指定套接字相关的选项
htonl() 将一个32位数从主机字节顺序转换为网络字节顺序
htons() 将一个16 位数从主机字节顺序转换为网络字节顺序
inet_addr() 将一个用网际标准点分表示法表示的字符串地址转换成网际地址值
inet_ntoa() 将一个网际地址值转换成一个用点分十进制表示法表示的字符串地址ioctlsocket() 为套接字提供控制
listen() 在指定套接字上监听外来连接
ntohl() 将一个32位数从网络字节顺序转换为主机字节顺序
ntohs() 将一个16 位数从网络字节顺序转换为主机字节顺序
recv()从一个连接的套接字上接收数据
recvfrom()从一个连接或未连接的套接字上接收数据
select()执行多路同步I/O
send()给一个连接套接字发送数据
sendto()给一个连接或未连接套接字发送数据
setsockopt() 设置与指定套接字相关的选项
shutdown() 关闭全双工连接的一部分
socket() 建立一个通讯用的末端点,返回一个套接字
注:标红函数作用在阻塞套接字上可以阻塞。
这些函数根据功能的不同可以分为如下几类:
(1) 套接字函数。此类函数包括socket(),bind(),getpeername(),getsockname()和closesocket(),它们主要完成创建,关闭套接字功能,以及对套接字命名与名字获取。
(2) 网络连接函数。此类函数包括listen() ,accept(),connect()和shutdown(),它们完成网络连接(如虚电路)的建立与关闭。此类函数中有部分可阻塞。
(3) 数据传输函数。此类函数包括send(),recv() ,sendto()和recvfrom() ,它们完成网络数据的发送与
接收,全部是可以阻塞的函数。
(4) 字节定序函数。此类函数包括htonl(),htons(),ntohl()和ntohs(),它们完成主机/网络之间数据字节顺序的转换。
(5) 地址转换函数。此类函数包括inet_addr(),inet_ntoa(),它们完成网络字符串地址和Internet 地址之间的转换。
(6) 套接字控制函数。此类函数包括getsockopt(),setsockopt(),ioctlsocket()和select(),它们设置/获取套接字的选项,控制/检测套接字的工作状态。其中select()函数在必要时可能阻塞。
只使用了上述函数Berkeley Sockets 源程序基本上可以不加修改地移植到Windows Sockets 环境中来。但是,移植过来的程序有一个最大的问题是“阻塞”。在Berkeley Sockets 中,套接字默认的工作模式是操作处于阻塞方式,一个阻塞操作可能阻塞整个Windows 环境。在非抢先Windows环境,强烈推荐程序员使用非阻塞(异步)操作,也就是说,推荐使用Windows Sockets 提供的异步选择函数代替可能阻塞的select()函数,并且用网络事件消息来驱动可能阻塞的网络连接函数(accept()和connect())和数据传输函数,这样设计的程序能更好地工作。
1.1.2 数据库函数
Windows Sockets定义了如表1.2 所示的“数据库”函数:
表 1.2 Windows Sockets 1.1 版本定义的“数据库”函数
函数名说明
gethostbyaddr() 通过网络地址获取主机名字和地址等信息
gethostbyname() 通过主机名字获取主机名字和地址等信息
gethostname()获取本地主机名
getprotobyname() 通过协议名获取协议名和协议号等信息
getprotobynumber() 通过协议号获取协议名和协议号等信息
getservbyname() 通过服务名获取服务的名字和端口等信息
getservbyport() 通过端口获取服务的名字和端口等信息
注:标红函数在某些条件下可以阻塞。
提供这类函数是为了获取网络特定的信息,在最初的Berkeley版本中,它们是作为在文本数据库文件中寻信息的机构。在Windows Sockets实现中,可能使用了不依赖于本地数据库文件的方法(如域名服务),但是对应用程序来说请求这些信息的格式是一致的,并且对应用程序来说是透明的。
调用这些函数所获得的信息存放在由Windows Sockets实现分配的一个结构中,函数返回此结构的地址。因此,应用程序可以通过此结构指针获取所需要的信息,但它决不能试图修改此结构,更不能释放结构的任一部分。另外,对一个线程来说,Windows Sockets实现只分配了结构的一个备份,任何Windows Sockets API 调用都可能修改此结构。也就是说,结构指针指向的数据只在此线程的下一次Windows Sockets API 调用之前才是正确的,应用程序应该在发布任何其它Windows Sockets API 调用之前将任何需要的信息拷贝出来。
数据库函数除gethostname()之外都是阻塞的,Windows Sockets提供它们是为了Berkeley Sockets网络程序的可移植性。在设计实现Windows Sockets 应用程序时,推荐使用Windows Sockets 提供的数据库函数的异步版本。
1.2 标准Socket 函数
1.2.1 accept()
语法:SOCKET WSAAPI
accept ( IN SOCKET s,
OUT struct sockaddr FAR* addr,
OUT int FAR* addrlen );
此函数用于从套接字上接收一个连接。它提取挂在套接字s 上的连接队列中的第一个连接,创建一个和s 有相同属性(包括使用函数WSAAsyncSelect()或WSAEventSelect()注册的异步事件,但不包括监听套接字的套接字组ID)的新数据套接字,并返回一个指向新套接字的句柄。如果连接队列上没有等待的连接,并且套接字没有标志为非阻塞,那么accept() 阻塞调用直到出现一个连接。如果套接字标志为非阻塞,并且队列上没有等待的连接,那么accept()返回错误WSAEWOULDBLOCK。新创建的数据套接字不能用来接收更多的连接,它只能用于数据传输;原来的套接字仍然打开,处于监听连接状态。
参数描述:
s,这是一个套接字描述符,该套接字在用作accept()函数的参数前必须先调用过listen()函数,此时它正处于监听连接的状态。
addr ,一个可选的指向缓冲区的指针,用来接收连接实体的地址,在通讯层使用。addr的确切格式由套接字创建时建立的地址族决定。
addrlen ,一个可选的指向整数的指针,它调用时含有地址addr指向的空间的大小,返回时含有返回的地址的确切长度(字节数)。
返回值:如果没有错误发生,accept()返回一个SOCKET类型的值,表示接收到的套接字的描述符。否则返回值INVALID_SOCKET,错误码可通过调用WSAGetLastError()函数得到。
错误码:
WSANOTINITIALISED :未初始化Windows Sockets DLL,在使用此函数之前必须有一次成功的WSAStartup()函数调用。
WSAENETDOWN: Windows Sockets 实现检测到网络系统已经失败。
WSAEFAULT: 参数addrlen 太小(小于结构sockaddr 的大小),或参数addr不是用户地址空间的合法部分。
WSAEINTR:此(阻塞)调用已被WSACancelBlockingCall()函数取消。WSAEINPROGRESS:一个阻塞的Windows Sockets 操作正在进行。
WSAEINVAL:在accept()调用之前没有执行过listen()。
WSAEMFILE:accept()队列入口空,但没有文件描述符可用(即打开的文件描述符过多)。WSAENOBUFS:无缓冲区空间可用。
WSAENOTSOCK:描述符s不是套接字描述符。
WSAEOPNOTSUPP:s 指向的套接字不是一种支持面向连接服务类型的套接字。WSAEWOULDBLOCK:套接字标志为非阻塞,但现在没有接收到连接。
注释:该调用只能和基于连接的套接字类型如SOCK_STREAM 一起使用。如果参数addr 和/或addrlen 等于NULL,那么没有关于接收套接字的远程地址信息返回。
参见:bind(), connect(), listen(), select(), socket(), WSAAsyncSelect(), WSAAccept()。
1.2.2 bind()
语法:int WSAAPI
bind ( IN SOCKET s,
IN const struct sockaddr FAR* name,
IN int namelen );
此函数用于未连接的数据报或流套接字,它将一本地地址与套接字连接,即建立半相关。当一套接字用socket()创建后,它存在于一名字空间(地址族), 但它没有赋予名字。bind()通过将一本地名字赋予一未命名的套接字, 建立起套接字的本地连接(主机地址/端口号)。
参数描述:
s,指示未连接的数据报或流套接字的描述符。
name,赋给套接字的本地地址(名字)。结构sockaddr 定义如下:
struct sockaddr { u_short sa_family;
char sa_data[14];
}; //除sa_family 外,其它内容都以网络字节顺序表示。namelen,地址缓冲区长度。
返回值:如果没有错误发生,bind()返回0。否则返回值SOCKET_ERROR,错误码可通过调用WSAGetLastError()函数得到。
错误码:
WSANOTINITIALISED:未初始化Windows Sockets DLL,在使用此函数之前必须有一次成功的WSAStartup()函数调用。
recv函数WSAENETDOWN :Windows Sockets 实现检测到网络系统已经失败。WSAEADDRINUSE:指定的地址已使用(参见setsockopt()中的SO_REUSEADDR 套接字选项)。WSAEADDRNOTAVAIL:对于本机器来说,指定的地址是非法地址(WinSock 2)。WSAEFAULT:参数namelen 太小(小于结构sockaddr 的长度);参数name 或namelen 不是用户地址空间的合法部分;参数name 包含了相关的地址族来说是不正确的地址
格式;参数name 指向的内存块的前两个字节与套接字描述符s 相关的地址族不
匹配。
WSAEINPROGRESS:一个阻塞的Windows Sockets 操作正在进行。WSAEAFNOSUPPORT:此套接字不能使用指定地址族中的地址(WinSock 1.1)。WSAEINVAL:此套接字已经捆扎到了一个地址。
WSAENOBUFS:无缓冲区空间可用,连接太多。
WSAENOTSOCK:此描述符不是套接字描述符。
注释:在Internet地址族中,一个名字有几个部分。对于SOCK_DGRAM和SOCK_STREAM类型的套接字来说,名字分为三部分:主机地址,协议号(分别默认设置为UDP和TCP),以及一个标志应用程序的端口号。在WinSock 2 中,参数name 并不严格地解释为指向“sockaddr”结构的指针,但为了与Windows Sockets的兼容性仍用这种表示。服务提供者可以把它当作一个指向长度为namelen的内存块而自由处理,在此内存块的前两个字节(对应结构sockaddr 定义中的sa_family 元素)必须为包含建立套接字的地址族,否则将产生错误WSAEFAULT。
如果应用程序不关心赋予它的地址,则可指定一个等于常数INADDR_ANY的网际地址,和/或等于0 的端口。如果网际地址等于INADDR_ANY,任何合适的网络接口都可用,这就简化了在多宿主机上的应用程序设计。当一个服务器向几个网络提供服务时,这将变得很重要。在不指定地址的情况下,服务器可以接收发向其端口的所有UDP数据包和TCP 连接请求,而不必关心请求是从哪一个网络接口到达的。如果端口指定为0,Windows Sockets 实现将为应用程序指定一界于1024 和5000 之间的端口值。应用程序可在bind() 后使用getsockname()来得到赋给它的地址,但要注意的是,对于网际地址等于INADDR_ANY 的情况,getsockname()只有当套接字连接后才填入网际地址(Internet address),原因是当主机是多地址家族时,几个网际地址都是合法的。对客户应用程序来说,不鼓励将其绑扎到一个指定的端口,因为这样存在与已
经使用了该端口的其它套接字冲突的危险。
由于Windows Sockets 只支持AF_INET 地址域,因此名字缓冲区的格式只能是sockaddr_in 结构。此结构在winsock.h 中定义如下:
struct in_addr{ u_long s_addr; };
struct sockaddr_in{ u_char sin_len;
u_char sin_family; // 只能置为AF_INET
u_short sin_port; //应用程序必须连接的端口号
struct in_addr sin_addr; // sin_addr 字段为主机网际地址
char sin_zero[8]; }; // sin_zero 扩展未用,必须全为0
注意,此结构的任何字段均为网络字节顺序。
在WinSock 2,支持的地址族得到扩展,因此结构sockaddr不只解释为sockaddr_in,根据不同的地址族,它有不同的确切格式。
参见:WSACancelBlockingCall(), connect(), listen(), getsockname(), setsockopt(), socket()。
1.2.3 closesocket()
语法:int WSAAPI
closesocket ( IN SOCKET s ); // s,待关闭的套接字描述符
此函数关闭套接字s,并释放分配给该套接字的资源,以后对s 的引用都将产生错误WSAENOTSOCK。如果s 涉及一个打开的TCP 连接,该连接被释放。
返回值:如果没有错误发生,closesocket()返回0。否则返回值SOCKET_ERROR,错误码可通过调用WSAGetLastError()函数得到。
错误码:
WSANOTINITIALISED:未初始化Windows Sockets DLL,在使用此函数之前必须有一次成功的WSAStartup()函数调用。
WSAENETDOWN:Windows Sockets 实现检测到网络系统已经失败。
WSAENOTSOCK:此描述符不是套接字描述符。
WSAEINPROGRESS:一个阻塞的Windows Sockets 操作正在进行。
WSAEINTR:此(阻塞)调用已被WSACancelBlockingCall()函数取消。WSAEWOULDBLOCK:套接字标志为非阻塞并且SO_LINGER 设置为非零超时。
注释:closesocket()函数的语义受套接字选项SO_LINGER 和SO_DONTLINGER 的影响,具体见下表(默认情况下是允许SO_DONTLINGER):
选项SO_DONTLINGER SO_LINGER SO_LINGER
间隔不用零非零关闭类型Graceful Hard Graceful
等待关闭?No No Yes
如果SO_LINGER设置(例如,linger结构的l_onoff域非零)并且超时间隔为零(l_linger为零),那么即使队列数据尚未发送或确认,closesocket()函数也不会阻塞。这称作强制(“hard”或“abortive”)关闭,因为套接字的虚电路立即复位,任何未发送的数据都将丢失,并且在虚电路远程方的任何recv()调用都将以WSAECONNRESET失败。在这种情况下,套接字不进入TCP 状态机的三次握手流程,系统资源被立即释放。这对于服务器应用程序非正常退出后希望能立即启动很有用,当正常通信中不鼓励使用。
如果SO_LINGER设置超时间隔为非零,closesocket()函数将阻塞,直到剩余的数据都发送完毕或直到超时退出,这称作“雅致”(graceful )关闭。注意如果套接字设置为非阻塞并且SO_LINGER设置为非零超时,调用closesocket()将失败,错误码为WSAEWOULDBLOCK。
如果SO_DONTLINGER 设置在流套接字上(例如,linger 结构的l_onoff 域为零), closesocket()调用将立即返回。然而,排队等待传送的任何数据如果可能的话都将在该套接字关闭前发送出去,这也称作“雅致”关闭。注意在这些情况下,Windows Sockets 实现可能会在任意时间内不释放套接字和其他资源, 这可能影响希望使用全部可用套接字的应用程序。如果应用程序要确保连接上的所有数据都被发送或接收到,则应该在调用closesocket() 函数之前调用shutdown()函数。
下面给出closesocket()函数的小结:
•如果SO_DONTLINGER 允许(默认设置),且不会出现错误WSAEWOULDBLOCK──连接在后台“雅致”关闭;
•如果SO_LINGER允许并且超时间隔为0,则总是立即返回──连接被重置或终止;
•如果SO_LINGER允许并且超时间隔非0:
──对于阻塞套接字,阻塞到所有数据发送完或超时间隔到时;
──对于非阻塞套接字,立即返回并且指示错误WSAEWOULDBLOCK。
参见:accept(), socket(), ioctisocket(), setsockopt(),WSAAsyncSelect(),WSADuplicateSocket()。
1.2.4 connect()
语法:int WSAAPI
connect ( IN SOCKET s,
IN const struct sockaddr FAR* name,
int namelen );
此函数用来与对等方建立一个连接。如果套接字s 没有绑扎,则系统赋予本地相关一个唯一值,并且套接字被表示为已绑扎的。
参数描述:
s,用来表示发出连接请求的套接字的描述符。
name,指向一个socket address结构的指针,该结构含有对等方的套接字的地址。
namelen , name指向的socket address结构的字节数。
返回值:如果没有错误发生,connect()返回0。否则返回值SOCKET_ERROR,错误码可通过调用WSAGetLastError()函数得到。对于阻塞套接字来说,返回值表示连接试图是否成功.对于非阻塞套接字来说,连接试图不一定马上完成。当connect()返回SOCKET_ERROR,并且WSAGetLastError()返回WSAEWOULDBLOCK 时,应用程序可以:
1.利用select()函数,通过检查套接字是否可写来判断连接请求是否完成。
2.如果应用程序已使用WSAAsyncSelect()函数注册了对连接事件的兴趣,则当连接操作完成
时应用程序将收到FD _CONNECT通知(无论成功与否)。
3.如果应用程序已使用WSAEventSelect()函数注册了对连接事件的兴趣,则当连接操作完成
时相应的事件对象将设置信号(无论成功与否)。
对于一个非阻塞套接字来说,在连接试图完成之前,任何对该套接字的connect()调用都将以错误码WSAEALREADY 失败,在连接成功之后则返回错误码WSAEISCONN 。由于Windows Sockets 1.1 规范在定义当连接请求正在处理时调用connect()函数返回的错误值有二义性,其返回值对于不同的Windo
ws Sockets实现其值不同,因此不推荐应用程序采用多次调用connect()函数的方式来检测连接是否完成。如果应用程序员一定要这么做,为了确保程序的可靠运行,他们在处理错误码WSAEALREADY 的同时,还必须准备处理WSAEINVAL 和WSAEWOULDBLOCK 错误码。
如果返回值指出连接试图失败(例如WSAECONNREFUSED ,WSAENETUNREACH ,WSAETIMEDOUT等),则应用程序可对该套接字再次调用connect()函数。
错误码:
WSANOTINITIALISED:未初始化Windows Sockets DLL,在使用此函数之前必须有一次成功的WSAStartup()函数调用。
WSAENETDOWN:Windows Sockets 实现检测到网络系统已经失败。
WSAEADDRINUSE:套接字的本地地址已被使用,并且该套接字没有使用SO_REUSEADDR 来设置允许地址重用。此错误经常发生在函数bind()调用时,但当bind()函数使
用通配地址(包括ADDR_ANY)并且在connect()函数调用时需要“提交”一
个指定地址时,此错误能够延迟到connect()函数。
WSAEINTR:阻塞的WinSock 1.1 调用为WSACancelBlockingCall()函数撤消。WSAEINPROGRESS:一个阻塞的Windows Sockets 1.1 操作正在进行。
WSAEALREADY:一个非阻塞的connect()调用已经在指定的套接字上进行(WinSock 2)。WSAEADDRNOTAVAIL:远程地址非法(如ADDR_ANY)。
WSAEAFNOSUPPORT:此套接字不能使用指定地址族中的地址。WSAECONNREFUSED:连接请求被目的主机拒绝。
WSAEDESTADDRREQ:要求目标地址(WinSock 1.1)。
WSAEFAULT:参数name或namelen不是用户地址空间的合法部分;参数namelen太小(小于结构sockaddr的长度);参数name包含了相关的地址族来说是不正确的地址格式。WSAEINVAL :此套接字没有捆扎到一个地址,或套接字为监听套接字,或者指定的目的地址与套接字从属的强制组不一致。
WSAEISCONN:此套接字已经建立了连接(只对面向连接的套接字有效)。
WSAEMFILE:无文件描述符可用(WinSock 1.1)。
WSAENETUNREACH:此主机现在不能到达网络。
WSAENOBUFS:无缓冲区空间可用,此套接字不能被连接。
WSAENOTSOCK:此描述符不是套接字描述符。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论