Socket 初步
1 TCP chat server 程序:
import socket from socket import SOL_SOCKET,SO_REUSEADDR sk = socket.socket() # 设置socket的可选项, 允许port重复绑定,防止程序非正常推出时, 再次运行时操作系统尚未解除端口占用。 sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sk.bind(('127.0.0.1', 8090)) sk.listen() print('TCP chat Server is running...') conn, addr = sk.accept() print('%s user is connected...'%addr[0]) while True: content = conn.recv(1024).decode('utf-8') print(content) if content == 'bye': conn.send(b'bye') break info = input('>>>') conn.send(bytes(info, encoding='utf-8')) conn.close() sk.close()
TCP client 程序:
import socket sk = socket.socket() sk.connect(('127.0.0.1',8090)) sk.send(bytes('你好!', encoding='utf-8')) while True: ret = sk.recv(1024).decode('utf-8') print(ret) if ret == 'bye': sk.send(b'bye') break info = input('>>>') sk.send(bytes(info,encoding='utf-8')) sk.close()
2 UDP socket , chat server 举例
3 TCP 的 文件传输, 使用struct 解决黏包问题
Server 端:
import socket import struct import json import os buffer = 512 sk = socket.socket() ip_port = ('127.0.0.1', 8090) sk.bind(ip_port) sk.listen() conn, addr = sk.accept() print('%s user is connected...'%addr[0]) pack_head = conn.recv(4) head_len = struct.unpack('i',pack_head)[0] json_head = conn.recv(head_len).decode('utf-8') head = json.loads(json_head) file = head['filename'] filesize = head['filesize'] copysize = filesize with open(file,'wb') as f: while True: if filesize >= buffer: cont = conn.recv(buffer) f.write(cont) filesize -= buffer else: cont = conn.recv(filesize) f.write(cont) break conn.close() print('filesize is %d'%head['filesize']) print('file get size %d'%os.path.getsize(file)) print('copysize is %d'%copysize) if head['filesize'] == os.path.getsize(file): print('接收文件 %s 成功。。。'%file) else: print('接收文件 %s 失败。。。'%file)
Client 端:
import socket import os import struct import json buffer = 512 sk = socket.socket() ip_port = ('127.0.0.1', 8090) sk.connect(ip_port) filepath = r'C:\Users\cuiyu\Documents\pythonclass\01 Python全栈9期(第一部分):基础+模块+面向对象+网络编程\day01' filename = r'01 python fullstack s9day1 自我介绍今日内容大纲.mp4' file = os.path.join(filepath,filename) filesize = os.path.getsize(file) head = {'filepath': filepath,'filename': filename,'filesize':filesize} json_head = json.dumps(head) byte_head = bytes(json_head, encoding='utf-8') head_len = len(byte_head) pack_len = struct.pack('i', head_len) sk.send(pack_len) sk.send(byte_head) with open(file,'rb') as f: while True: if filesize >= buffer: cont = f.read(buffer) sk.send(cont) filesize -= buffer else: cont = f.read(filesize) sk.send(cont) break print('传送完毕。。。') sk.close()
注意: buffer = 1024 以上的数据时会出现传输的接收问题, 猜测可能与写盘的速度有关。适当降低buffer 的大小可以解决此问题。
4 hmac 验证socket客户端的合法性
Server 端:
import os import socket import hmac sk = socket.socket() sk.bind(('127.0.0.1', 8090)) sk.listen() secret_key = b'egg' conn, addr = sk.accept() def check_login(conn): msg = os.urandom(32) h = hmac.new(secret_key, msg) h_digest = h.digest() conn.send(msg) client_digest = conn.recv(1024) return hmac.compare_digest(h_digest, client_digest) ret = check_login(conn) if ret: print('合法的客户端') else: print('非法的客户端') conn.close()
Client 端:
import socket import hmac secret_ket = b'egg' sk = socket.socket() sk.connect(('127.0.0.1',8090)) msg = sk.recv(1024) h = hmac.new(secret_ket,msg) client_digest = h.digest() sk.send(client_digest) print('已发送hmac认证') sk.close()
5 socketserver 模块
import socketserver class MySocketServer(socketserver.BaseRequestHandler): def handle(self): print(self.request.recv(1024).decode('utf-8')) # self.request 就是 conn if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1', 8090),MySocketServer) server.serve_forever()