一些概念
套接字:
套接字(socket)也叫通信端点,最初用于计算机内部进程之间的通信,而随着网络的发展,套接字被用于计算机之间的通信。举个例子,你(是一台计算机)要打电话给你的朋友(另一台计算机),你只有朋友的电话号码可不行,还得有台电话,而这台电话就相当于一个套接字。
套接字有两种一种基于文件,一种基于网络。基于文件可以简单理解为用于进程通信的,基于网络的可以简单理解为用于计算机之间的通信的。而他们又被分为了不同的地址家族(address family,抽象的名字),如AF_UNIX,AF_INET... 既然是python网络编程,先把重点放在AF_INET(使用ipv4)上。
额...还有一个概念,有连接和无连接套接字。有连接使用TCP ,套接字类型为SOCK_STREAM,无连接使用UDP,套接字类型为SOCK_DGRAM。
socket 实现简单的C/S
现在的开发一般都用的时socketserver,但我是一个初学者所以决定从socket编写一些简单的脚本开始学习。
先用socket来模拟一下C/S建构的基本通信。首先是服务器端,当然这分为TCP和UDP服务器,先来TCP的练习。作为一个TCP服务器,首先要等一个来自客户端的连接。然后和客户端建立连接,最后才是和客户端进行通讯。socket有很多属性,这里列出几种常用的属性,这也是我们需要的属性。
socket(family,type,proto)
family 是地址家族,我们使用AF_INET,当然这也是默认值,type我们使用SOCK_STREAM,这也是默认值,最后一个proto参数暂时用不到,先不考虑。
bind(address)
该方法用来绑定服务端的ip
和port
但是只接受一个参数,所以需要把ip
和port
打包为一个元组传入即可。
listen()
该方法启动服务器开始监听
accept()
该方法等待一个客户端的连接请求,如果有客户端请求连接,那么该方法就会生成一个连接对象,并且将该对象和客户端的ip
作为返回值返回。当连接对象被创建,服务端和客户端就可以开始交互了。当然当accept()
创建了一个对象后,会重新回到原始的状态去等待新的连接,新的连接到来时又会重复上述过程。
recv(buffer)
该方法用于接收数据buffer
为接收数据的大小。当然数据的类型为bytes
send(bytes)
发送数据,发送的也是bytes
先例举这么多,下面开始第一个程序,生活需要仪式感,起一个 NB 的名字 Binary_TCPserver_V1
# Binary_TCPserver_V1 import socket from time import ctime server = socket.socket() server.bind(("localhost",6969)) server.listen() # starting listen print('waiting connection...') conn,addr = server.accept() # wait the connect in ... # and return a connection representing and a ip address data = conn.recv(1024) print("Server recive data:",data) conn.send(b'[%s] %s'% (data,ctime().encode('utf-8'))) # send a bytes type not a str server.close()
我们接收来自客户端的一组数据,然后返回该数据加当前的时间,显然这不是一个合格的服务端程序,它接受完一次连接请求进行一次和客户端的交互后就退出了,服务端是不应该退出的。但是为了试一下该程序的逻辑是否正确,写一个简单的客户端和它交互一下。
# Binary_TCPclinet_V1 import socket clinet = socket.socket() clinet.connect(('localhost',6969)) send_data = input('>>:') # type is string clinet.send(send_data.encode('utf-8')) # change type to bytes data = clinet.recv(1024) # buffersize 1024 Byte print("Clinet recive data:",data.decode()) clinet.close()
先运行服务端,然后运行客户端,客户端返回
>>:i am binary
Clinet recive data: [i am binary] Mon Dec 9 17:06:41 2019
服务端返回
waiting connection... Server recive data: b'i am binary'
看到我们已经实现了简单的交互,但是,不能客户端说了一句话服务端返回然后就结束了这次谈话吧。我们要让服务器一直运行下去,客户端说够了再退出而不是说一句就连接断开了。上Binary_TCPserver_V2
while True: print('waiting connection...') conn,addr = server.accept() # wait the connect in ... # and return a connection representing and a ip address while True: data = conn.recv(1024) if not data: print('clinet has broken the connection...') break print("Server recive data:",data) conn.send(b'[%s] %s'% (data,ctime().encode('utf-8'))) # send a bytes type not a str server.close()
其实就是加了两个循环而已,客户端代码,一次交互个够的那种。
# Binary_TCPclinet_V1 import socket clinet = socket.socket() clinet.connect(('localhost',6969)) while True: send_data = input('>>:') # type is string if not send_data: break clinet.send(send_data.encode('utf-8')) # change type to bytes data = clinet.recv(1024) # buffersize 1024 Byte print("Clinet recive data:",data.decode()) clinet.close()
测试,客户端
>>:i am binary Clinet recive data: [i am binary] Mon Dec 9 18:15:50 2019 >>:i am handsome Clinet recive data: [i am handsome] Mon Dec 9 18:15:58 2019 >>:
服务器端
waiting connection... Server recive data: b'i am binary' Server recive data: b'i am handsome' clinet has broken the connection... waiting connection...
看到我们已经基本实现了一个单线程服务器了,这当然不是最终目的。有了这个基础,不必太过纠结还有很多的关于socket不会的内容。我们开始进军socketserver
这才是最终的目的。
url: socketserver我来啦
url:一些关于socket有趣的小栗子