在网络通信中socket几乎无处不在,它可以看成是应用层与TCP/IP协议簇通信的中间软件抽象层,是两个应用程序彼此进行通信的接口,并且把复杂的TCP/IP协议细节隐藏在接口之后。Python提供了socket模块,可以非常方便的进行socket编程。
使用socket方法创建一个新的socket,通常提供两个参数,第一个参数是address family, 第二个是socket type。
以上创建了一个address family为IP协议,并且传输协议为TCP的socket。
服务器端在创建一个socket之后,需要绑定到一个IP地址与端口,提供服务,这就要用到bind方法。
使用listen方法,将socket设置为监听状态。listen方法后面跟一个参数,表示最多可以在队列里面接收的请求数目。
现在,我们已经创建了一个server socket,然后编写一个无限循环体,接收来自客户端的连接,利用accept方法,它返回一个新的socket,表示与远端的连接,同时返回一个地址对,表示远端连接的IP地址与端口号。
通常,循环体中的server socket不会发送和接收任何数据,而仅仅是接收来自远端的连接,将新的连接交给其他的线程去处理,然后就继续侦听更多其他的连接,否则的话在处理一个连接的时候,就无法接受其他新的连接了。
接下来,我们新建一个线程对连接进行处理。首先,使用recv方法接受来自socket的数据,后面带着一个参数表示一次最多可以接受数据的大小。然后使用sendall方法回复socket,sendall不断发送数据直到所有数据发送完毕或者发生了异常。最后,需要记得把socket关闭,因为每个socket就代表了系统中的一个文件描述符,如果没有及时关闭,可能会超过系统最大文件描述符的数量,导致无法创建新的socket。
总结server socket主要由以下几个步骤:
以下是完整的server socket示例代码:
客户端的socket就比较简单,主要包括以下几个步??:
IO多路复用是指,先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已经准备好进行I/O时,该函数才返回。在返回时,它告诉进程哪些描述符已经准备好可以进行I/O。
Python的select模块提供了IO复用的功能,如select和poll等都能够执行I/O多路复用。
select方法的调用形式如下:
前面3个参数表示我们正在等待的对象,即我们所关心的文件描述符:
第4个参数是可选的超时时间的秒数,如果没有选择超时参数,那么一直等待直到至少可以文件描述符准备就绪。如果超时时间设置为0,那么完全不等待,测试所有指定的描述符并立即返回,而不阻塞。
select方法返回的是一个三元组的列表表示准备好的对象。 一个示例程序: server端等待至少一个socket就绪:
client端,创建两个socket向server发送消息:
Unix系统的中poll()比select()有着更好的可扩展性,也就是说同时可以支持更多的客户端连接。因为poll()系统调用只需真正感兴趣的那些文件描述符,而select()是通过位图将感兴趣的文件描述符在位图中对应的bit置1,然后需要线性扫描位图中所有的bit。所以select()复杂度是O(N),而poll()是O(M),其中N是最大文件描述符个数,M是目前的文件描述符个数,通常M < N。
一个示例程序:
Python的select模块中提供的select()和poll()函数几乎可以被大多数操作系统支持,此外模块还提供了epoll()和kqueue()函数,但是仅仅限于一部分的操作系统,epoll()仅支持Linux 2.5.44及之后的系统,而kqueue()运行于BSD系统。
本文示例的完整代码,可在GitHub下载查看。
下面关于Python的文章您也可能喜欢,不妨看看: