一、Winsock
Winsock是一个基于Socket模型的API,在Windows系统中广泛应用;它在Berkeley接口函数的基础上,还增加了基于消息驱动机制的Windows扩展函数;Winsocket1.1只支持TCP/IP网络,Winsock2.2增加了对更多协议的支持。
需要包含头文件Winsock2.h,需要使用库2s2_32.lib,包含办法可以用语句告诉编译时调用库:
#pragma comment(lib,”ws2_32.lib”);
二、Windows Socket的启动
使用函数WSAStartup()完成操作;
此函数的格式:int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
三、创建套接口socket()
应用程序在使用套接口通信前,必须要拥有一个套接口,使用Socket()函数来给应用程序创建一个套接口。
SOCKET socket(int af, int type, int protocol);
协议 | 地址族 | 套接口类型 | 套接口类型使用的值 | 协议字段 |
互联网协议(IP) | AF_INET | TCP | SOCK_STREAM | IPPROTO_TCP |
UDP | SOCK_DGRAM | IPPROTO_UDP | ||
RAW | SOCK_RAW | IPPROTO_RAW , IPPROTO_ICMP |
四、指定本地地址------bind()
当socket()创建了一个套接口之后,需要将该套接口与该主机上提供服务的某端口联系在一起,bind()函数用于完成这样的绑定工作。
Int bind(SOCKET s, const struct scokaddr FAR*name, int namelen); // 参数2 sockaddr_in结构指定IP地址和端口信息
五、服务器启动监听------listen()函数
在一个服务器端用socket调用成功后一个套接口,并用bind函数和一个指定的地址关联后,就需要指示该套接口进入监听连接请求状态,这需要通过listen函数来实现。
Int listen( SOCKET s, int backlog);
六、客户端请求连接-----connect函数
Int connect(SOCKET s, const struct sockaddr FAR*name, int namelen);
七、服务器端接受连接------accept()函数
SOCKET accept(SOCKET s, struct scokaddr FAR* addr, int FAR*addrlen);
八、发送数据------send()函数
Int send(socket s, const char FAR* buf, int len, int flags);
九、接受数据------recv()函数
Int recv(SOCKET S, char FAR*buf, int len, int flags);
十、无连接的套接口上接收数据------recvfrom()
Int recvfrom(SOCKET s, char FAR*buf, int len, int flags, struct sockaddr FAR*from, int FAR* fromlen);
十一、在无连接套接口上发送数据-sendto()
Int sendto(SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to,int tolen);
十二、关闭读写通道------shutdown()函数
Int shutdown(SOCKET s, int how); // how: 0 1 2
十三、关闭套接口------closesocket()函数
Shutdown函数只关闭读写通道,并不关闭套接口,且套接口所占有资源将被一直保留到closesokcet调用之前。
Int closesocket( SOCKET s);
十四、IP地址转换函数
1. Char *inet_ntoa(struct in_addr in); // 把32位数字表示为IP地址
2. Unsigned long inet_addr(const char FAR * cp); // 把IP地址转换为32位数字
3.u_long htonl(u_long hostlong); // 4 bytes
4.u_short htons(u_short hostshort); // 2bytes
5.u_long ntohl(u_long netlong); // 4bytes
6.u_short ntohs(u_short netshort); // 2bytes
十五、终止使用Winsock—WSACLeanup()函数
当应用程序不再使用Winsock API中的任何函数时,必须调用WASCeanup()将其从Windows Socket的实现中注销,以释放为此应用程序或DLL分配的任何资源。
第二节
一、 面向连接的C/S程序工作流程(TCP)
1. 服务器端工作流程
l 使用WSAStartup()函数检查系统协议栈安装情况
l 使用socket()函数创建服务器通信套接口
l 使用bind()函数将创建的套接器与服务器地址绑定
l 使用listen()函数使用服务器接口做那接收连接请求的准备
l 使用accept()接收来自客户端由connect()函数发出的连接请求
l 根据连接请求建立连接后,使用send()函数发送数据,或者使用recv()函数接收数据
l 使用closesocket()函数关闭套接口中,也可以先使用shutdown()函数先关闭读写通道
l 最后调用WSACeanup()函数结束Winsock Sockets API
2. 客户端程序工作流程
l 使用WSAStartup()函数检查系统协议栈安装情况
l 使用socket()函数创建客户端套接口
l 使用connect()函数发出也服务器建立连接请求(调用前可以不用bind()端口号,由系统自动生成完成)
l 连接建立后使用send()函数发送数据,或使用recv()函数接收数据
l 使用closesocket()函数关闭套接口
l 最后调用WSACleanup()函数,结束Winsock Sockets API
3. 服务器与客户端五元组的建立
五元组 | 《协议》 | 《本地IP地址,本地端口号》 | 《远程IP地址,远程端口号》 |
服务器五元组 | 由socket()确定 | 由服务器端调用bind()时确定 | 由accept()确定 |
客户端五元组 | 由socket()确定 | 由客户端的bind()调用确定。如果客户端没有进行bind()调用,或调用了bind()但没有指定具体的地址或端口,则由系统内核自动确定地址和端口 |
|
4.面向连接的C/S程序工作流程图(TCP)
二、 无连接的C/S程序工作流程(UDP)
1、 无连接的数据报传输服务通信时,客户端与服务器端所使用的函数是类似的,其工作流程如下:
l 使用WSAStartup()函数检查系统协议栈的安装情况
l 使用socket()函数创建套接口,以确定协议类型
l 调用bind()函数将创建的套接口与本地地址绑定,确定本地地址和本地端口
l 使用sendto()函数发送数据,或者使用recvfrom()函数接收数据
l 使用closesocket()函数关闭套接口
l 调用WSACleanup()函数,结束Windows Sockets API
2.注意事项:
l 通信一方可以不用bind()绑定地址和端口,由系统分配
l 不绑定IP地址和端口号的一方必须首先向绑定地址的一方发送数据
l 无连接的应用程序也可以调用connect()函数,但是它并不向对方发出建立连接的请求,而是在本地返回,由内核将connect()中指定的目标IP地址和端口号记录下来,在以后的通信中就可以使用面向连接的数据发送函数send()和数据接收函数recv().
l 无连接的数据报传输过程中,作为服务器一方必须先启动
l 无连接客户端一般不调用connect(),在数据发送前客户与服务器各自通过socket()和bind()建立了半相关,发送数据时除指定本地套接口的地址外,还需要指定收方套接口地址,从而在数据收发过程中动态建立全连接。
三、阻塞通信与非阻塞通信
阻塞方式:套接字进行I/O操作时,函数要等待到相关的操作完成以后才能返回,对提高处理机的利用率不利,但编程简单。
非阻塞方式:套接字进行I/O操作时,无论操作成功与否,调用都会立即返回。
阻塞方式编程简单,一个套接口的默认操作模式为阻塞,可以调用函数ioctlsocket()进行设置。
三、并发服务器