1、Winsock的启动和终止
调用WSAStartup,协商Winsock的版本支持和分配必要的资源。
调用WSACleanup终止对Winsock DLL的使用,并释放资源。
2、错误检查和控制
获取错误信息:WSAGetLastError。
3、Winsock编程模型
⑴流套接字编程模型
①服务器进程创建套接字。SOCKET socket(int af, int type, int protocol)
af一般取AF_INET
type这里取SOCK_STREAM
protocol一般取0
②将本地地址绑定到所创建的套接字上以在网络上标识该套接字。
int bind(SOCKET s,const struct sockaddr* name,int namelen)
s标识一未绑定套接字的句柄,用来等待客户机的连接;
name是赋予套接字的地址,由struct sockaddr结构表示:
struct addr
{
u_short sa_family;
char sa_data[14];
};
更常用的为sockaddr_in
Struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
其中sin_family为AF_INET,
sin_port指定服务端口,
sin_addr用于把IP地址保存为一个4字节的数,
sin_zero充当填充项。
namelen表示name的长度。
③将套接字置入监听模式并准备接受连接请求。
int listen(SOCKET s, int backlog)
s标识一个已绑定未连接套接字的描述字,
backlog指定正在等待连接的最大队列长度,
进入监听状态后,调用accept函数使套接字作好接受客户连接的准备
SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);
s是处于监听模式的套接字描述字,
第二个参数是一个有效的SOCKADDR_IN结构的地址,
addrlen是SOCKADDR_IN结构的长度,
该函数返回一个新的套接字描述字,它对应于已经接受的那个客户机连接,该客户机的所有操作都是用这个套接字。
④客户进程调用socket函数创建客户端套接字。
⑤客户向服务进程发出连接请求,通过connect函数建立一个端的连接。
int connect(SOCKET s, const struct sockaddr FAR *name, int namelen)
s标识一个未连接的数据报或流类套接字的描述字,
name标识进程IP地址信息,
namelen标识name参数的长度
(常见错误:
WSAEADDRNOTAVAIL:地址全为0;
WSAECONNREFUSED:目标计算机没有侦听指定端口的这一进程;
WSAETIMEDOUT:连接超时。)
⑥连接请求到来后,accept函数生成一个新的套接字与客户套接字建立连接,并向客户返回接受信号。
⑦客户机接收到服务器的接受信号时表示已连接成功,用send、recv函数进行数据的收发:
int send(SOCKET s, const char* buf, int len, int flags);
s是已建立连接的套接字描述字,发送数据操作将在这个套接字上
进行,
buf是字符缓冲区,包含即将发送的数据,
len指定即将发送的缓冲区内的字符数,
flags可取:0,MSG_DONTROUTE或MSG_OOB或它们的“或”,
send函数返回发送数据的字节数,发生错误就返回SOCKET_ERROR,
常见错误是WSAECONNABORTED:虚拟回路由于超时或协议错误而中断,此时应关闭这个套接字
int recv( SOCKET s , char* buf , int len , int flags);
s是准备接收数据的套接字,
buf是即将收到数据的字符缓冲区,
flags可取:0,MSG_PEEK,MSG_OOB或它们的“或”,
recv函数返回发送字节数。
⑧关闭套接字。
先调用shutdown函数防止数据丢失:
int shutdown( SOCKET s, int how)
how用于描述禁止哪些操作:SD_RECEIVE、SD_SEND、SD_BOTH。
再调用closesocket函数关闭套接字,释放资源:
int closesocket( SOCKET s)
⑵数据报套接字编程模型
服务端:
用socket建立套接字
用bind把这个套接字和准备接收数据的IP地址信息绑定
用recvfrom接收数据报:
int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen)
from是一个SOCKADDR结构指针,fromlen是带有指向地址结构的长度的指针。
发送端:
建立一个套接字
调用sendto函数发送:
int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen)
buf是发送数据的缓冲区
len指明发送的字节数
最后调用closesocket函数释放套接字资源。