Winsock学习----面向连接的协议(一)

套接字有三种类型:流式套接字, 数据包套接字和原始套接字。其中流式套接字定义了一种可靠的面向连接的服务,实现了无差错无重复的顺序数据传输。数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。原始套接字允许对底层协议如ip和ICMP直接访问,主要用于新的网络协议实现测试等。

服务器API函数:

“服务器”其实就是一个进程, 它需要等待任意数量的客户端连接,以便为他们的请求提供服务。对服务器监听的连接来说,“服务器”必须在一个已知的名字上。在TCP/IP中, 这个名字就是本地接口的IP地址, 并加上一个端口号。每一种协议都有一套不同的定址方案,所以会有不同的命名方法。在Winsock中, 第一步是将指定的套接字绑定到它已知的名字上。这个过程是通过API调用bind来完成。下一步是这个套接字设置为监听模式。这时,用API函数listen来完成的。最后,若一个客户试图建立连接,服务器必须通过accept或者WSAAccept调用接受连接

1.bind函数:

int bind(

SOCKET s,

const struct sockaddr FAR* name,

int namelen

s  代表我们希望在上面等待客户端连接的套接字。

name 它的 是一个指向struct sockaddr 类型的指针。sockaddr中包含了名字的地址和端口信息,以及使用的协议等。

namelen 这个参数表示的是 sockaddr 的大小。

示例代码:

SOCKET s;

struct sockaddr_in tcpaddr;

int port = 5150;

int nSockErr;

s = socket(AF_INET, SOCK_SREAM, IPPROTO_TCP);

tcpaddr.sin_family = AF_INET;

tcpaddr.sin_port = htons(port);

tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(s, (SOCKADDR*)&tcpaddr, sizeof(tcpaddr)) == SOCKE_ERROR)

{

nSockErr = WSAGetLastError();

}

这个例子中创建了一个流套接字。随后, 设置了TCP/IP地址结构, 一边在它上面接受客户端连接。在这种情况下套接字绑定到端口5150上的默认IP接口。

一旦出错。bind就会返回SOCKET_ERROR。对bind来说最常见的错误是WSAEADDRINUSE。如果使用的是TCP/IP,那么WSAEADDRINUSE就代表另一个进程已经同本地IP接口和端口绑定到一起。或者那个IP或者端口号正处于TIME_WAIT状态。假如在调用bind的时候套接字已经绑定过了,便会返回WSAEFFAULT错误。

2.listen函数

int listen(

SOCKET s,

int backlog

);

第一个参数同样是绑定过的套接字。

第二个参数指定了正在等待连接的最大队列长度。这个参数非常重要,因为完全可能同时出现几个客户端连接请求。如果backlog为2,如果有3个客户端同时发出请求,那么头两个会被放在等待处理的队列中,以便应用程序能依次处理。而第三个请求连接会得到WSAECONNREFUSED错误。注意,一旦服务器接收了一个连接,那个连接就会从等待队列中删除掉,以便能接收继续接收请求。backlog本身的就存在着限制,这个限制是有基层的协议提供者决定的。如果出现非法值,会用最近进合法值取代。除此之外,对于如何知道实际的bakclog,其实并不存在一个标准手段。

listen的错误:listen的错误常见的有WSAEINVAL。这个错误意味着忘记在listen之前调用bind。

3.Accept和WSAAccept

SOCKET accept(

SOCKET s, 

struct FAR* addr,

 int FAR* addrlen

);

第一个参数 是一个已经处于监听状态的套接字。

第二个参数 是一个指向 sockaddr或者sockaddr_in 类型的指针, 这个结构体用来保存客户端的信息。

第三个参数 表示sockaddr或者sockaddr_in 结构的大小

通过调用accept函数,可以为上述等待队列中的第一个连接请求提供服务。accept函数返回后,addr结构中包含发出请求的客户端的ip地址信息。此外accept还会返回一个新的套接字描述符,它对应这已经接受连接的客户端连接。对于该客户端之后的所有操作都应该使用这个套接字。至于原来的监听套接字仍然处于监听状态。如果INVALID_SOCKET,这是我们需要调用WSAGetLastError已得到更多的错误细节。

SOCKET sServSock;

sockaddr_in addr;

int nSockErr;

int nNumConns[5];

SOCKET sConns[5];

sockaddr Connaddrs[5];

int nAddrLen = sizeof(sockaddr);

sServSock = socket(AF_INET, SOCK_SREAM, 0);

addr.sin_family = AF_INET;

addr.sin_port = hton(5050);

addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(sServSock, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKE_ERROR)

{

nSockErr = WSAGetLastError();


}

if(listen(sServSock, 2) == SOCKET_ERROR)

{

nSockErr = WSAGetLastError();

}

while( (nNumconns<5))

{

sConns[nNumConns] = accept(sServSock, ConnAddrs[nNumConns],&nAddrLen);

if(sConns[nNumConns] == INVALID_SOCKET)

{

nSockErr = GetLastError();

}

else

{

nNumConns++;

}

}











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值