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()
模拟SSH

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()

socket 粘包

当 send 被调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的 socket 发送缓冲区里,等缓冲区满了、或者数据等待超时了,数据才会被 send 到客户端,这样就把好几次的小数据拼成一个大数据,统一发送到客户端了,这么做的目地是为了提高IO利用效率,一次性发送总比连发好几次效率高嘛。但也带来一个问题,就是“粘包”,即2次或多次的数据粘在了一起统一发送了。

解决方法:

  1. 让数据等待超时,发送一次数据之后 sleep(0.5)(直接忽略)
  2. 不要连续 send ,可以用 recv 将多次 send 隔开,只需要数据接收端接收到一次数据后,send 回复发送端
  3. 如果之前知道传输数据的大小,直接接收那么多的数据
传输大文件

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()

socket server 多并发

多线程: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()

Python socket & socket server的更多相关文章

  1. Python中socket经ssl加密后server开多线程

            前几天手撸Python socket代码,撸完之后经过ssl加密,确保数据的安全,外加server端开启多线程保证一个客户端连接有一个线程来服务客户端,走了不少的弯路,网上的信息啥的要 ...

  2. Python socket 基础(Server) - Foundations of Python Socket

    Python socket 基础 Server - Foundations of Python Socket 通过 python socket 模块建立一个提供 TCP 链接服务的 server 可分 ...

  3. python从socket做个websocket的聊天室server

    下面的是server端:把IP改成自己的局域网IP: #coding:utf8 import socket,select import SocketServer import hashlib,base ...

  4. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

  5. python之socket-ssh实例

    本文转载自大王http://www.cnblogs.com/alex3714/articles/5830365.html 加有自己的注释,应该会比原文更突出重点些 一. 基本Socket实例 前面讲了 ...

  6. python之socket

    一.初识socket      socket 是网络连接端点,每个socket都被绑定到一个特定的IP地址和端口.IP地址是一个由4个数组成的序列,这4个数均是范围 0~255中的值(例如,     ...

  7. Python:socket

    Socket:又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯. socket()函数 Pyt ...

  8. python之socket开发

    socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Un ...

  9. Python网络socket学习

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

随机推荐

  1. 【西北师大-2108Java】第九次作业成绩汇总

    [西北师大-2108Java]第九次作业成绩汇总 作业题目 面向对象程序设计(JAVA) 第11周学习指导及要求 实验目的与要求 (1)理解泛型概念: (2)掌握泛型类的定义与使用: (3)掌握泛型方 ...

  2. WPF 精修篇 DataGrid 筛选

    原文:WPF 精修篇 DataGrid 筛选 DataGrid也可以分组 但是用的地方不多 就没写 筛选还是可以的 比如Datagrid数据量比较大 要做数据筛选 贴码 <DataGrid x: ...

  3. HDU2899Strange fuction(二分/三分)

    传送门 题目大意:求 F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100):的最小值 题解:求个导,二分导函数零点,就是原函数最小值所在的 ...

  4. php date获取当前时间

    结果: 结论: 本以为第一种方式最快,第三种方式竟超乎想象的快且稳定

  5. js的事件循环(Event Loop)

    (本文从掘金小册整理) 首先介绍一下几个概念 进程与线程 相信大家经常会听到 JS 是单线程执行的,但是你是否疑惑过什么是线程? 讲到线程,那么肯定也得说一下进程.本质上来说,两个名词都是 CPU 工 ...

  6. 网络聊天室---node.js中net网络模块TCP服务端与客户端的使用

    //1.简单创建 net服务器 // const net = require("net"); // const server = net.createServer((c)=> ...

  7. Kettle-动态数据链接,使JOB得以复用

    动态数据连接,使JOB得以复用 背景 移动执法系统在目前的主要的部署策略为1+N的方式,即总队部署一套,地市各部署一套,且基本都在环保专网.各地市的业务数据需要推送到总队系统,以便总队系统做整体的监督 ...

  8. ASP.NET Core 如何用 Cookie 来做身份验证

    前言 本示例完全是基于 ASP.NET Core 3.0.本文核心是要理解 Claim, ClaimsIdentity, ClaimsPrincipal,读者如果有疑问,可以参考文章 理解ASP.NE ...

  9. 记一次Python与C#的AES加密对接

    前言 这几天做自动化测试的同事找到我,说是帮她看看有个AES加密的问题要怎么处理. 大概就是文档中贴了一段C#的AES加密代码,然后她要翻译成python的版本,去做一些测试相关的工作. 在我印象中, ...

  10. [算法]LeetCode 152:乘积最大子序列

    题目描述: 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4]输出: 6解释: 子数组 [2,3] 有最大乘积 6.示 ...