网络中我们采用客户端/服务器结构的方式,其中服务器就是为一个或多个客户端提供服务,它唯一的目的就是等待客户端的请求,并响应请求,然后等待更多的请求;而客户端因特定的请求而联系服务器,并发送数据,然后等待服务器的回应,最后完成请求或给出故障的原因。
网络编程的一个基本组件是套接字(socket)。最初它是为同一个主机上的应用程序所创建,也就是应用在进程间的通信上面。今天我们要说的是它在网络通信中的应用,所以有两种类型的套接字:基于文件和面向网络的!
因为两个进程运行在同一个台计算机上,所以这些套接字都是基于文件的。这意味着文件系统支持它们的底层基础结构。由于文件系统是一个运行在同一主机上的多个进程之间的共享常量,所以这也是说的通的。
基于网络的套接字有自己的家族名字AF_INET,或者地址家族:因特网。另一个地址家族是AF_INET6。
套接字分为面向连接和无连接的!
面向连接的套接字意味着你在通信前必须先建立一个连接,面向连接的通信提供序列化的、可靠的和不重复的数据交付,而没有记录边界。这基本上意味着每条信息可以拆分成多个片段,并且每一条消息片段都确保能够到达目的地,然后将它们按顺序组合在一起,最后将完整消息传递给正在等待的应用程序。
实现上面的连接形式主要协议是传输控制协议(TCP)。为了创建TCP套接字,必须使用SOCK_STREAM作为套接字类型。TCP套接字的名字SOCK_STREAM基于流套接字的其中一种表示。
无连接的套接字是数据报类型的,这意味着通信开始前不需要建立连接。这样在数据的传输过程中无法保证它的顺序性、可靠性和重复性。但是数据报保存了记录边界,这意味着消息是以整体发送的。
既然有这么多副作用,为什么还要采用数据报的形式呢?由于面向连接的套接字所提供的保证,因此它们的设置以及对虚拟电路连接的维护需要大量的开销。然而,数据报不需要这些开销,这样它们通常能提供更好的性能,对某些应用程序更加合适。
实现无连接的套接字的主要协议是用户数据报协议(UDP),创建UDP的套接字,必须使用SOCK_DGRAM作为套接字类型。
在python中,我们为了看到其原理,利用socket模块来实现其过程。
from socket import * from time import ctime '''创建TCP服务器''' host = '' port = 12345 bufsize = 1024 addr = (host,port) tcpSersock = socket(AF_INET,SOCK_STREAM) #创建TCP/IP套接字 tcpSersock.bind(addr) #套接字与地址绑定 tcpSersock.listen(5) #监听连接 while True: #服务器无限循环 print('waiting for connection...') tcpSersock, addr = tcpSersock.accept() #接收客户端连接 print('...connecteg from:',addr) while True: data = tcpSersock.recv(bufsize) #接收数据 if not data: break tcpSersock.send('{} {}'.format(bytes(ctime(),'utf-8'),data)) #发送数据 tcpSersock.close() #关闭客户端套接字 tcpSersock.close() #关闭服务器套接字(可选)所有的套接字都是通过socket.socket()函数来创建的。因为服务器需要占用一个端口并等待客户端的请求,所以它们必须绑定一个本地地址。
from socket import * '''创建TCP客户器''' host = 'localhost' port = 12345 bufsize = 1024 addr = (host,port) tcpClisock = socket(AF_INET,SOCK_STREAM) #创建TCP/IP套接字 tcpClisock.connect(addr) #尝试连接服务器 while True: #客户器无限循环 data = input('> ') #输入数据 if not data: break tcpClisock.send(data) #发送数据 data = tcpClisock.recv(bufsize) if not data: break print(data.decode('utf-8')) tcpClisock.close() #关闭客户端套接字
