一、 Socket概念
Socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据互相传递。
我们知道网络通信都是基于IP+Port方能定位目标的具体服务,操作系统有0-65535个端口,每个端口都是独立对外提供服务;建立一个socket必须至少有2端,一个服务端,一个客户端,服务器端被动等待并接收请求,客户端主动发起请求,连接建立后,就可以互相发送数据了。
二、Socket功能类型
1、Socket Families (地址簇)
地址簇即地址的种类比如 IPv4、IPv6等。
Socket.AF_INET IPv4
Socket.AF_INET6 IPv6
Socket.AF_UNIX Unix本机进程间通信
2、Socket Types
Socket类型,例如tcp、udp等
socket.SOCK_STREAM 表示tcp
socket.SOCK_DGRAM 表示udp
socket.SOCK_RAW 原套接字,普通套接字无法处理ICMP、IGMP等网络报文,而SCOK_RAW可以,其次,SOCK_RAW也可以处理特殊的IPV4报文,此外,利用套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报单不保证顺序。SOCK_RAM用来提供原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文,SOCK_RAM通常仅限于高级用户或者管理员运行的程序使用。
3、Scoket方法
s = socket.socket(famliy=AF_INET,type=SOCK_STREAM)#声明一个socket s.bind(('0.0.0.0',8000)) #绑定IP和端口 s.listen(5) #监听的请求数 conn,client_addr = s.accept() #接受连接并返回,其中conn是新的套接字对象,可以用来接收和发送数据。client_addr是连接客户端的地址,接收Tcp客户的连接(阻塞式)等待连接的到来。 s.connect(('localhost',8000)) #连接到address的套接字,一般address的格式为元组,如果连接错误,返回socket.ERROR错误。 s.close #关闭套接字 s.recv()#接收消息,数据已字符串的形式返回,bufsize指定最多可接收的数量。 s.send()#将string中的数据发送到连接的套接字,以b的格式发送,但是在返回之前会尝试发送所有数据,成功返回None,失败则抛出异常
4、SocketServer 方法
首先定义一个类,然后这个socket类继承Socketserver.BASeRequestHandler,例如
import scocketserver class MySocketHandler(socketserver.BaseRequesHandler): def handle(self): while True: self.data = self.request.recv(1024).strip() print(self.client_addrss[0]) print(self.data) if not self.data:#这里判断是为了解决,当客户端断开后,服务端循环接受空的数据的。 print('client closed...') break self.request.send(self.data.upper())#在这里是将接收到的都变为大写返回给客户端。 if __name__ == '__main__': HOST,PORT = '0.0.0.0',9000 server = socketserver.ThreadingTCPServer((HOST,PORT),MySocketHandler)#这里使用ThreadingTCPServer是同时接受多个客户端的请求,并可以同时接受和发送数据 server.serve_forever()
5、Socketserver常见问题
(1)客户端关闭时,服务端循环接受空值
这种问题,就可以在服务端返回数据之前做一个判断,判断如果是空值就直接break跳出while循环。 import socketserver class MySocketHandler(socketserver.BaseRequestHandler): def handle(self): while True: self.data = self.request.recv(1024).strip() print(self.client_address[0]) print(self.data) if not self.data: #在这里解决不接收空值 print('client closed...') break self.request.send(self.data.upper())
(2)socketserver粘包的问题
这里有两个解决方法: 1、在粘包的位置sleep 1-5秒,虽然可以解决粘包的问题,但是通常不会这么干,总体来看,这样会无缘故的降低程序的效率。 2、在粘包的位置客户端随意发送一个值,然后随意接受一个值,并不做任何处理即可。