winsock编程(三)

 四.socket函数
Windows sockets函数socket建立一个socket。

SOCKET socket(

int af,

int type,

int protocol

);

参数
af[in] 一个地址簇。

type[in] socket的类型,有SOCK_STREAM和SOCK_DATAGRAM两种类型。

SOCK_STREAM 提供连续的、可靠的、双向的、基于连接的字节流的数据传输机制。使用TCP协议。

SOCK_DATAGRAM 支持数据报,数据报是面向非连接的、不可靠的、大小固定的数据。使用UDP协议。

protocol[in] 使用指定地址簇中的一个特别的协议。

注意
socket函数建立一个socket描述符,底层服务来分配资源和绑定socket。

返回值
若没有错误,socket函数返回一个指向新建的socket的描述符。否则,返回INVALID_SOCKET,你可以用WSAGetLastError函数获取错误码。

错误码
WSANOTINITIALISED 未初始化,请先调用WSAStartup初始化socket。

WSAENETDOWN 网络底层系统错误。

WSAEAFNOSUPPORT 地址簇不支持。

WSAEINPROGRESS 线程被阻塞,或者在回调。

WSAEMFILE socket操作符不可用。

WSAENOBUFS 没有缓冲区可用。

WSAEPROTONOSUPPORT 不支持的协议。

WSAEPROTOTYPE 协议类型错误。

WSAESOCKTNOSUPPORT 协议类型不受地址簇支持。

五.bind函数
Windows sockets函数bind关联一个本地地址到一个socket。

int bind(

SOCKET s,

const struct sockaddr FAR* name,

int namelen

);

参数
s[in] 指明一个未绑定的socket的描述器。

name[in] 将sockaddr指定的地址赋值给socket。

namelen[in] 名称的长度。

注意
bind函数应用在调用connect或者listen函数之前的未连接的socket上。它用于绑定面向连接(流)或者面向无连接(数据报)socket上。当socket被socket()函数创建后,它就存在于一个名字空间(地址家族)中,只是它还是未命名的对象。使用bind函数来建立socket的本地关联,它赋值给socket一个本地名称。

当使用Internet地址簇时,一个名字包括三个部分:地址簇,主机地址,端口号,它们代表了一个应用程序。在windows socket2中,名字参数并不是严格的要求是sockaddr指针。为了和windows sockets1兼容,会做一些转换。服务提供者只需要关心name参数是一个指向长度是namelen的内存块即可。这个内存块的开始两个字节必须指出了地址簇(也就是sockaddr的第一个成员u_short sa_family,两个字节长),地址簇用来创建socket。否则,一个WSAEFAULT错误就会产生。

若一个程序并不关心分配给它的本地地址,可以给sockaddr的sa_data字段赋值ADDR_ANY。这样底层网络服务会自动提供可用的地址,这可能简化了多网卡主机的程序的开发。

对于TCP/IP协议而言,若sockaddr的端口字段port赋值的是0,底层服务会自动分配一个从1024到5000的可用端口。程序可以用getsockname来获取系统分配的地址和端口。若指定的地址是ADDR_ANY,getsockname在socket连接之前可能不能提供系统分配的地址,直到有可用的地址为止。客户端程序端口建议指定为0,否则可能指定的端口其他的程序正在使用而发生冲突。

返回值
若调用bind没有错误发生则返回0。否则它返回SOCKET_ERROR,你可以用WSAGetLastError来获取相关的错误码。

错误码
WSANOTINITIALISED 未初始化,请先调用WSAStartup初始化socket。

WSAENETDOWN 网络底层系统错误。

WSAEADDRINUSE 一个进程已经绑定了参数指定的地址和端口。

WSAEADDRNOTAVAIL 指定的地址在本机上不可用。

WSAEFAULT 参数name错误,不属于一个可用的地址空间。namelen太小,name参数包含的地址信息错误,或者name的开始两个字节和地址簇不匹配。

WSAEINPROGRESS 有阻塞的进程,或者windows系统正在调用一个回调函数。

WSAEINVAL socket已经绑定到了一个地址。

WSAENOBUFS 连接太多,没有可用的缓冲区。

WSAENOTSOCK 传入的不是一个socket。

六.sockaddr结构体
sockaddr结构体一定程度上依赖于所选择的协议簇。除了sa_family字段,sockaddr的内容是压缩成网络字节流的。

struct sockaddr{

u_short sa_famly;

char sa_data[14];

};

在windows socket2中,name参数并不是严格的指向sockaddr结构体。这样它可以完成windows socket的兼容。它在不同的协议簇中有不同的意义。仅仅要求的是前两个字节u_short是地址簇,并且总共的内存长度是namelen。

以下的结构体用于TCP/IP协议,其他的协议用法也相似。

struct sockaddr_in{

short sin_family;

u_short sin_port;

struct in_addr sin_addr;

char sin_zero[8];

};

注:
一般TCP/IP协议使用sockaddr_in结构体而不是用sockaddr。

sockaddr_in结构体的:

sin_family地址簇字段,一般是AF_INET。

sin_port端口字段,可以用::htons(2000)函数分配指定的端口,hostToNetShort的意思。也可以用sin_port=0来由系统分配可用的端口。

sin_addr地址字段是一个结构体in_addr,它是一个联合体,可以用:sin_addr.s_addr初始化sin_addr字段。而s_addr定义为:#define s_addr S_un.S_addr,也就是一个联合体。对于TCP/IP协议,sin_addr可以指定INADDR_ANY,意味底层协议自动分配地址。若需要指定ip地址,可以用::inet_addr(“10.1.1.1”)来分配指定的地址。

sin_zero是一个0填充,可以用memset(&sockaddr.sin_zero,0,sizeof(sockaddr.sin_zero))。

七.listen函数
windows sockets的listen函数将socket置于侦听状态,它侦听一个传入的连接。

int listen(

SOCKET s,

int backlog

);

参数:
s[in] 一个描述符,指定了一个绑定的、未连接的socket。

backlog[in] 最大的等待队列。若这个值是SOMAXCONN,那么底层服务会为socket分配一个最大的能接受的等待队列。没有提供标准的接口来获得能接受的最大等待队列。

注意:
为了接受连接,一个socket首先要用socket()函数来创建,然后调用bind()函数绑定到一个本地地址,一个backlog由listen来指定,然后传入的连接就可以用accept()来接受了。面向连接的socket,如SOCK_STREAM,是使用listen()函数的。当连接成功建立后,socket被置于“被动”模式。

listen函数典型的用法是在服务器端,它能一次接受多个连接。当一个新连接到达服务器,而等待队列满了,客户端程序会收到一个错误代码WSAECONNREFUSED。

若没有可用的socket描述符,listen函数继续执行。如果描述符可用了,后续的对listen或者accept的调用会重新填充当前队列,或者可能的话,侦听和接受连接。

程序可以在一个socket上多次调用listen函数。这会更新当前socket的等待队列(backlog)。应该指定更多的backlog,否则当前等待的连接会被重置和丢失。

返回值:
若listen调用成功,返回0。否则,返回SOCK_ERROR,可以调用WSAGetLastError函数获取一个错误代码。

错误码:
WSANOTINITIALISED 未初始化socket,请先调用WSAStartup函数。

WSAENETDOWN 底层网络系统错误。

WSAEADDRINUSE socket未绑定到合法的本地地址。

WSAEINPROGRESS 进程被阻塞。

WSAEINVAL socket未调用bind绑定。

WSAEISCONN socket已经处于连接状态。

WSAEMFILE 没有可用的socket描述符。

WSAENOBUFS 没有可用的缓冲。

WSAENOTSOCK 描述符不是一个合法的socket。

WSAEOPNOTSUPP 指向的socket不支持listen操作
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值