Winsock API 编程介绍上
作者/管理员 时间/2007-3-16 6:30:00 类别/设计 查看/
 发表评论 以论坛方式查看
标签:编程
相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程
中应用最广泛的编程接口Winsock API.

使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可
以直接使用Winsock API来写网络应用程序,但是,要写出优秀的网络
应用程序,还是必须对TCP/IP协议有一些了解的.

1. TCP/IP协议与Winsock网络编程接口的关系.

在开始之前,我们先说一下Winsock和TCP/IP到底是什么关系.

我碰到很多人问我:怎样使用Winsock协议编程? 其实,这话说的有点
错误,Winsock并不是一种网络协议,他只是一个网络编程接口,也就
是说,他不是协议,但是他可以访问很多种网络协议,你可以把他当作
一些协议的封装.现在的Winsock已经基本上实现了与协议无关.你可
以使用Winsock来调用多种协议的功能.

那么,Winsock和TCP/IP协议到底是什么关系呢?实际上,Winsock就是
tcp/ip协议的一种封装,你可以通过调用winsock的接口函数来调用
tcp/ip的各种功能.例如我想用Tcp/ip协议发送数据,你就可以使用
winsock的接口函数send()来调用tcp/ip的发送数据功能,至于具体
怎么发送数据,Winsock已经帮你封装好了这种功能.

2.TCP/IP协议介绍

现在来介绍一些tcp/ip的原理.tcp/ip协议包含的范围非常的广,他
是一种四层协议,包含了各种,硬件软件需求的定义,我们这里只介绍
软件方面的知识.tcp/ip协议确切的说法应该是tcp/udp/ip协议.

udp协议(User Datagram Protocol 用户数据报协议).是一种保护消
息边界的,不保障可靠数据的传输.
tcp协议(Transmission Control Protocol 传输控制协议).是一种
流传输的协议.他提供可靠的,有序的,双向的,面向连接的传输.

3.保护消息边界和流

那么什么是保护消息边界和流呢?

保护消息边界,就是指传输协议把数据当作一条独立的消息在网上
传输,接收端只能接收独立的消息.也就是说存在保护消息边界,接收
端一次只能接收发送端发出的一个数据包.
而面向流则是指无保护消息保护边界的,如果发送端连续发送数据,
接收端有可能在一次接收动作中,会接收两个或者更多的数据包.

我们举个例子来说,例如,我们连续发送三个数据包,大小分别是2k, 
4k , 8k,这三个数据包,都已经到达了接收端的网络堆栈中,如果使
用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有
三次接收动作,才能够把所有的数据包接收完.而使用TCP协议,我们
只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的
数据包接收下来.只需要有一次接收动作.

这就是因为UDP协议的保护消息边界使得每一个消息都是独立的.而
流传输,却把数据当作一串数据流,他不认为数据是一个一个的消息.

所以有很多人在使用tcp协议通讯的时候,并不清楚tcp是基于流的
传输,当连续发送数据的时候,他们时常会认识tcp会丢包.其实不然,
因为当他们使用的缓冲区足够大时,他们有可能会一次接收到两个甚
至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个
数据包,而已经接收的其他数据包却被忽略了.所以大家如果要作这
类的网络编程的时候,必须要注意这一点.

4。Winsock编程简单流程

下面我们介绍一下Win32平台的Winsock编程方法.
通讯则必须有服务器端,和客户端.
我们简单介绍tcp服务器端的大体流程.

对于任何基于Winsock的编程首先我们必须要初始化Winsock DLL库.
int WSAStarup( WORD wVersionRequested , LPWSADATA lpWsAData ).
wVersionRequested是我们要求使用的Winsock的版本.
调用这个接口函数可以帮我们初始化Winsock .然后我们必须创建一
个套接字(socket).
SOCKET socket( int af , int type , int protocol );
套接字可以说是Winsock通讯的核心.Winsock通讯的所有数据传输,
都是通过套接字来完成的,套接字包含了两个信息,一个是IP地址,一
个是Port端口号,使用这两个信息,我们就可以确定网络中的任何一
个通讯节点.

当我们调用了socket()接口函数创建了一个套接字后,我们必须把套
接字与你需要进行通讯的地址建立联系,我们可以通过绑定函数来实
现这种联系.
int bind(SOCKET s , const struct sockaddr FAR* name , int namelen ) ;
struct sockaddr_in
{
short sin_family ;
u_short sin_prot ;
struct in_addr sin_addr ;
char sin_sero[8] ;
}
就包含了我们需要建立连接的本地的地址,包括,地址族,ip和端口信
息.sin_family字段我们必须把他设为AF_INET,这是告诉Winsock使
用的是IP地址族.sin_prot 就是我们要用来通讯的端口号.sin_addr
就是我们要用来通讯的ip地址信息.

在这里,必须还得提一下有关'大头(big-endian)'小头(little-endian)'.
因为各种不同的计算机处理数据时的方法是不一样的,Intel 86处理
器上是用'小头'形势来表示多字节的编号,就是把低字节放在前面,
把高字节放在后面,而互联网标准却正好相反,所以,我们必须把主机
字节转换成网络字节的顺序.Winsock API提供了几个函数.

把主机字节转化成网络字节的函数;
u_long htonl( u_long hostlong );
u_short htons( u_short hostshort );
把网络字节转化成主机字节的函数;
u_long ntohl( u_long netlong ) ;
u_short ntohs( u_short netshort ) ;
这样,我们设置ip地址,和port端口时,就必须把主机字节转化成网络
字节后,才能用bind()函数来绑定套接字和地址.

当绑定完成之后,服务器端必须建立一个监听的队列来接收客户端的
连接请求.
int listen( SOCKET s ,int backlog );
这个函数可以让我们把套接字转成监听模式.
如果客户端有了连接请求,我们还必须使用
int accept( SOCKET s , struct sockaddr FAR* addr , int FAR* addrlen );
来接受客户端的请求.
现在我们基本上已经完成了一个服务器的建立,
而客户端的建立的流程则是初始化WinSock ,然后创建socket套接字
,再使用
int connect( SOCKET s , const struct sockaddr FAR* name , int namelen ) ;
来连接服务端.
查看该用户更多文章>>