3.7.6 面向连接的套接字编程举例
本小节介绍一个使用Windows套接字API编写的客户机/服务器的例子。例子中有两个程序,一个是套接字的服务器端程序,以下简称服务器程序;一个是套接字的客户机端程序,以下简称客户机程序,两者采用TCP协议通信。两个程序可以分别部署在两台主机上,也可以放在同一台主机上。
1.程序的功能
服务器程序启动后,监听来访的客户机的连接请求,当有来自客户机端的请求时,接收该连接请求,并将客户机端的IP地址打印出来。连接建立后,双方可以开始通信。客户机端程序在控制台上输入字符后,程序将字符发送到服务器端。服务器接收发自客户机端的字符后,在屏幕上进行回显,并将收到的字符发回给客户机,客户机收到后,将接收到的字符在屏幕上打印出来。
2.程序的启动
服务器端的程序启动时,需要手工指定监听端口号,启动的命令是
例如server.exe 90。端口号可自行指定。如果指定的端口号已经被占用,则程序报错退出。
客户机端的程序启动时,需要指定服务器端的IP地址和监听端口号。如果两个程序在同一台主机上,则可以将IP地址设置为127.0.0.1。启动的命令是
例如client.exe 202.112.107.65 90。当客户机端程序成功连接上服务器后,屏幕显示提示符。在提示符后可以输入字符。输入若干字符后回车,客户机端的程序将字符发送到服务器端,服务器端将显示收到的字符。
3.程序运行
程序运行过程如图3-38~图3-41所示。
图3-38 服务器端程序启动
图3-39 客户机端程序启动
图3-40 客户机端发送字符后回显
图3-41 服务器端接收到字符后回显
4.服务器端源代码
【例3-8】面向连接的服务器端示例源代码。
5.客户机端源代码
【例3-9】面向连接的客户机端示例源代码。
6.多线程的服务器程序
以上的两个例子演示了套接字函数的使用,但是值得注意的是,这个例子中的服务器程序只能为一个客户机端提供服务,当有一个客户机端程序已经连接上服务器后,再启动另一个客户机端进程去连接服务器时,发现它能连接上服务器,但是发送字符后并没有回显,如图3-42所示。这是什么原因呢?原来,这是由服务器端程序的代码决定的。服务器端的程序在接收了第1个客户机端进程的请求后,就进入了与第1个客户机的数据交互的处理逻辑。此时即使有新的连接请求到来,程序的代码也对此没有响应。
图3-42 第2个客户机端程序不能正常地与服务器端通信
这种服务器端程序与我们熟悉的“服务器”概念相去甚远。众所周知,一台互联网上的WWW服务器或者FTP服务器需要同时处理多个连接请求。在一些热门的站点上,一台服务器可能需要同时处理几百甚至几千个连接请求。那么怎么样才能做到这一点呢?采用多线程的方式可以同时处理与多个客户机端的通信。【例3-10】是一个多线程套接字服务器程序,在该服务器程序中,主程序负责监听客户机端的连接请求,当接收了一个客户机端的连接请求后,主程序即创建一个新的线程,这个新的线程负责处理该客户机端的后续数据交换过程。有多少个客户机端的连接请求就创建多少个新线程。多个线程并行工作,互相之间不影响。当其中一个客户机端进程退出后,其对应的服务器端线程也随之终止,但是并不影响其他的线程。通过这种方式,服务器端的程序就可以同时为多个客户机端服务了。
【例3-10】面向连接的多线程服务器端示例源代码。
代码说明
与单线程套接字服务器程序【例3-8】相比,多线程套接字服务器程序【例3-10】多了一些处理代码。在接收了客户机端的连接请求后,服务器主程序便通过调用Create Thread函数建立了一个新的线程,新的线程负责处理与此客户机端的后续数据交换,线程的处理逻辑在函数SocketServer Thread中体现。图3-43~图3-47描述了多线程服务器的工作过程。
图3-43 多线程服务器程序启动
图3-44 接收第1个客户机端的连接请求
图3-45 接收第2个客户机端的连接请求
图3-46 与第1个客户机端通信
图3-47 与第2个客户机端通信
7.Winsock
在以上的例子中,使用的是Windows平台下的套接字API,编程语言使用的是C++,有一些系统调用是Windows平台所要求的,如WSAStartup函数和WSACleanup函数,而在BSD UNIX操作系统上是不要求的。
Socket最早起源于BSD UNIX。20世纪70年代随着微软公司的崛起,Windows操作系统在个人计算机中逐渐占据统治地位。为了使原先在UNIX上才能实现的网络通信方式同样能在Windows上实现,Windows Socket编程接口被提出并得以建立。
Windows套接字(Winsock)是一个定义Windows网络软件应该接入网络服务的规范。通过这个规范,Windows应用程序可以实现强大的网络功能,这些功能都建立在WinSock接口的基础上,是Windows环境下应用广泛的、开放的、支持多种协议的网络编程接口。经过不断的完善,它已成为Windows网络编程事实上的标准规范。
Winsock规范继承了Berkeley库函数中很多优良风格,并在此基础上扩展了很多适应于Windows操作系统的扩展函数库。可以认为Winsock规范是Berkeley套接字规范的超集。
当然,为了适应Windows操作系统,Winsock规范对Berkeley套接字规范的一些部分进行了修改,诸如头文件、数据类型、函数名称、指针类型,等等。针对Windows操作系统基于消息的特点,Winsock规范还增加了对消息驱动机制的支持。
对于开发者来说,大部分在Berkeley套接字规范中的概念和方法在Winsock中仍然可以沿用,而涉及的一些具体的函数名称和数据类型等,需要去查找Winsock规范相关的技术资料。