Python socket & socket server

匿名 (未验证) 提交于 2019-12-02 22:51:08

socket

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket(套接字)。
建立网络通信连接至少要一对socket。socket是对TCP/IP的封装

步骤:
服务器端:

  1. 实例化类
  2. bind 绑定端口
  3. listen 监听端口
  4. accept 等待连接(阻塞)
    sock, addr = server.accept() sock 是为客户端实例化的socket类, addr 是客户端的地址
  5. 与客户端交互:recv 接收(阻塞)、send 发送数据
  6. close 断开连接

客户端:

  1. 实例化类
  2. connect 连接端口
  3. 与服务器端交互:recv 接收(阻塞)、send 发送数据
  4. close 断开连接

server:

import socket  server = socket.socket() server.bind(('localhost', 8001)) server.listen(3)  conn, addr = server.accept() data = conn.recv(1024) conn.send(b'Got') print('recv:', data)  server.close() 

client:

import socket  client = socket.socket() client.connect(('localhost', 8001)) client.send(b'Hello')  data = client.recv(1024) print('recv:', data)  client.close() 

server:

import socket  server = socket.socket() server.bind(('localhost', 8001)) server.listen(3) while 1:     conn, addr = server.accept()     print('new connection:', addr)     while 1:         data = conn.recv(1024)         conn.send(b'Got')         if not data:             break         else:             print('recv:', data)

client:

import socket  client = socket.socket() client.connect(('localhost', 8001))  while 1:     data = input('>>>').strip()     if len(data) == 0:         # 注意不能发送内容为空,否则客户端会卡住         continue     if data == 'e':         break     else:         client.send(data.encode('utf-8'))         data = client.recv(1024)         print('recv:', data.decode())  client.close()

server:

import socket import os  server = socket.socket() server.bind(('localhost', 8001)) server.listen(3) while 1:     try:         conn, addr = server.accept()         print('new connection:', addr)         while 1:             data = conn.recv(1024)             if not data:                 break             else:                 res = os.popen(data.decode()).read()                 conn.send(res.encode())     except ConnectionResetError:         continue 

client:

import socket  client = socket.socket() client.connect(('localhost', 8001))  while 1:     data = input('>>>').strip()     if len(data) == 0:         # 注意不能发送内容为空,否则客户端会卡住         continue     if data == 'e':         break     else:         client.send(data.encode('utf-8'))         data = client.recv(1024)         print(data.decode())  client.close() 

server:

import socket import os import hashlib  server = socket.socket() server.bind(('localhost', 8001)) server.listen(3) while 1:     try:         conn, addr = server.accept()         print('new connection:', addr)         while 1:             cmd = conn.recv(1024).decode()             if not cmd:                 print('lost client')                 break             else:                 file_name = cmd.split()[1]                 if not os.path.isfile(file_name):                     res = 'no such file'                 else:   # 存在可以传输的文件                     m = hashlib.md5()                     file_size = os.stat(file_name).st_size                     print(file_size)                     conn.send(str(file_size).encode())                     conn.recv(1024)                     with open(file_name, 'rb')as f:                         for line in f:                             conn.send(line)                             m.update(line)                     print('file md5:', m.hexdigest())                     conn.send(m.hexdigest().encode())     except ConnectionResetError:         print('lost client')         continue 

client:

import socket import hashlib  client = socket.socket() client.connect(('localhost', 8001))  while 1:     cmd = input('get filename: >>>').strip()     if len(cmd) == 0:         # 注意不能发送内容为空,否则客户端会卡住         continue     else:         client.send(cmd.encode('utf-8'))         file_name = cmd.split()[1]         received_size = 0         m = hashlib.md5()         total_size = client.recv(1024)         client.send(b'Get size')         f = open(file_name + '.new', 'wb')         while received_size < int(total_size.decode()):             size = int(total_size.decode()) - received_size             if size < 1024:                 receive_size = size             else:                 receive_size = 1024             data = client.recv(receive_size)             received_size += len(data)             f.write(data)             m.update(data)         else:             f.close()             print(m.hexdigest())             server_md5 = client.recv(1024).decode()             if m.hexdigest() == server_md5:                 print('file checked') client.close() 

有时结束连接之后再连接会显示端口占用,可以通过重用端口省去等待的时间:server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) (bind 端口之前进行设置)

socket server

创建socketserver的基本步骤:

  1. 创建一个请求处理类,继承 BaseRequestHandler 并且重写父类中的 handle()
  2. 实例化 TCPServer ,将 server IP 和请求处理类传给 TCPServer
  3. 调用 server.handle_request() #只处理一个请求 server.serve_forever() #处理多个一个请求,永远执行
  4. server_close()
class BaseServer:  class TCPServer(BaseServer): class UDPServer(TCPServer):  class UnixStreamServer(TCPServer): class UnixDatagramServer(UDPServer):  class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
import socketserver   class MyTCPHandler(socketserver.BaseRequestHandler):     def handle(self):         # 处理和客户端所有的交互         pass   if __name__ == '__main__':     HOST, PORT = 'localhost', 8001     server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)     server.serve_forever() 

如果要设置允许地址重用:
allow_reuse_address 是 TCPServer 和 UDPServer 的类变量,之后又被实例化的类继承了,由于实例化的类继承父类的同时已经开始 bind,所以只能在他继承父类之前修改父类的类变量

HOST, PORT = 'localhost', 8001 socketserver.TCPServer.allow_reuse_address = True server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)  # 实例化 bind listen server.serve_forever()

多线程:ThreadingTCPServer
多进程:ForkingTCPServer -only in Linux

使用时只需在实例化类时继承其中一个:

HOST, PORT = 'localhost', 8001 socketserver.TCPServer.allow_reuse_address = True server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)  # 实例化 bind listen server.serve_forever()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!