socket通讯
socket是什么?
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
socket和file的区别:
- file模块是针对某个指定文件进行【打开】【读写】【关闭】
- socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭
 
更多功能
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
参数一:地址簇
socket.AF_INET IPv4(默认)
socket.AF_INET6 IPv6socket.AF_UNIX 只能够用于单一的Unix系统进程间通信
参数二:类型
socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDPsocket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务参数三:协议
0 (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
web服务应用demo
1 #!/usr/bin/env python 2 #coding:utf-8 3 import socket 4 5 def handle_request(client): 6 buf = client.recv(1024) 7 client.send("HTTP/1.1 200 OK\r\n\r\n") 8 client.send("Hello, World") 9 10 def main(): 11 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 sock.bind(('localhost',8080)) 13 sock.listen(5) 14 15 while True: 16 connection, address = sock.accept() 17 handle_request(connection) 18 connection.close() 19 20 if __name__ == '__main__': 21 main()
一、利用socket实现简单的即时通讯
server端:
1 #! usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 server = socket.socket() 7 8 server.bind(('127.0.0.1', 8888)) 9 server.listen(5) 10 # print("before") 11 while True: 12 print("before") 13 conn, addr = server.accept() # 等待链接 14 conn.sendall(bytes("welcome, hanhan...", encoding='utf-8')) # python3.0之后必须是bytes类型 15 while True: 16 ret_byte = conn.recv(1024) 17 ret_str = str(ret_byte, encoding='utf-8') 18 if ret_str == 'q': 19 break 20 conn.sendall(bytes(ret_str + 'good', encoding='utf-8')) 21 print(addr) 22 print("after")
client端:
1 #! usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 client = socket.socket() 7 8 client.connect(("127.0.0.1", 8888)) 9 result_byte = client.recv(1024) 10 print(str(result_byte, encoding='utf-8')) 11 12 while True: 13 inp = input("Enter:") 14 if inp == 'q': 15 client.sendall(bytes(inp, encoding='utf-8')) 16 break 17 else: 18 client.sendall(bytes(inp, encoding='utf-8')) 19 ret = client.recv(1024) 20 print(str(ret, encoding='utf-8'))
二、使用socket实现文件上传
server端:
1 import socket 2 3 server = socket.socket() 4 5 server.bind(('127.0.0.1', 9999)) 6 7 server.listen(5) 8 print("before") 9 while True: 10 conn, addr = server.accept() 11 # 接受文件大小 12 size = str(conn.recv(1024), encoding='utf-8') 13 total_size = int(size) 14 print(total_size) 15 has_size = 0 16 # 先等待接收接收客户端发送的消息后,再去接收数据,避免粘包问题 17 ret = str(conn.recv(1024), encoding='utf-8') 18 print(ret, 'start recving data...') 19 f = open('f1.png', 'wb') 20 while has_size <= total_size: 21 content = conn.recv(1024) 22 f.write(content) 23 has_size += len(content) 24 f.close()
client端:
1 import socket 2 import os 3 client = socket.socket() 4 5 client.connect(('127.0.0.1', 9999)) 6 # 先获取文件大小,并发送给服务端 7 size = os.stat('f.png').st_size 8 print(size) 9 client.sendall(bytes(str(size), encoding='utf-8')) 10 # 发送文件前,先和服务端进行通讯,完成后在传输文件,避免粘包问题 11 client.sendall(bytes("start sending data...", encoding='utf-8')) 12 print("start sending data...") 13 with open('f.png', 'rb') as f: 14 for line in f: 15 client.sendall(line) 16 17 print(os.stat('f.png').st_size) 18 print(os.stat('f1.png').st_size)
三、使用socket server实现简单的并发
1 #! usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socketserver 5 6 7 class Myserver(socketserver.BaseRequestHandler): 8 def handle(self) -> None: 9 # self.request, self.client_address, self.server 10 print("before...") 11 conn = self.request 12 conn.sendall(bytes("welcome, hanhan...", encoding='utf-8')) 13 while True: 14 ret_byte = conn.recv(1024) 15 ret_str = str(ret_byte, encoding='utf-8') 16 if ret_str == 'q': 17 break 18 conn.sendall(bytes(ret_str + 'good', encoding='utf-8')) 19 # print(addr) 20 print("after") 21 22 23 if __name__ == '__main__': 24 server = socketserver.ThreadingTCPServer(('127.0.0.1', 9999), Myserver) 25 server.serve_forever()
四、I/O多路复用
I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
一、 python中的应用
python是通过其内置的select模块,它提供了select,poll,epoll三个方法,通过调用系统的select,poll,epoll方法实现;
Windows Python:
    提供: select
Mac Python:
    提供: select
Linux Python:
    提供: select、poll、epoll
注意⚠️:网络操作、文件操作、终端操作等均属于IO操作。windows只支持socket操作,其他系统支持其他的IO操作,但是无法检测,普通文件操作自上次是否发生变化;
对于select方法:
1 句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间) 2 3 参数: 可接受四个参数(前三个必须) 4 返回值:三个列表 5 6 select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。 7 1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中 8 2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中 9 3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中 10 4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化 11 当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。
server端
server.py
1 #! usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socket 4 import select 5 6 sk1 = socket.socket() 7 sk1.bind(('127.0.0.1', 9999)) 8 sk1.listen(5) 9 10 sk2 = socket.socket() 11 sk2.bind(('127.0.0.1', 9998)) 12 sk2.listen(5) 13 14 server_list = [sk1, sk2] 15 while True: 16 r_list, w_list, e_lirt = select.select(server_list, [], [], 1) 17 ''' 18 rlist -- wait until ready for reading 19 wlist -- wait until ready for writing 20 xlist -- wait for an ``exceptional condition'' 21 ''' 22 for sk in r_list: 23 conn, addr = sk.accept(1024) 24 conn.sendall(bytes('hello', encoding='utf-8')) 25 conn.close()
client端
client.py
1 #! usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socket 4 5 client = socket.socket() 6 7 client.connect(('127.0.0.1', 9999)) 8 print(str(client.recv(1024), encoding='utf-8'))
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号