在socket的server端处理client端发来的数据
一、楔子
最近做了一个需求遇到一个坑,归结成一个小问题,其实就是在socket的server端处理client端发来的数据的问题,现将这个问题总结一下,本文将数据在server端以字典的形式存储。
另外,由于我想做一个动图的演示,所以本文没有用MarkDown写,希望本文的干货能弥补格式带来的不适ε=(´ο`*)))
二、基于原生UDP的实现
我们这里用“默认字典”去实现数据的构建,基于原生UDP的代码如下:
# -*- coding:utf-8 -*-
import socket
from collections import defaultdict server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1',9002))
print('Listening......') client_msg = {
'':'Naruto',
'':'Sasuke',
} dic_msg = defaultdict(list) while 1:
try:
# 接收
recv_msg,addr = server.recvfrom(1024)
recv_msg = recv_msg.decode('utf-8')
# 这里只切割一次,避免后面的数据还有|符号
cid = recv_msg.strip().split('|',1)[0]
msg = recv_msg.strip().split('|',1)[1] # 默认字典
dic_msg[client_msg[cid]]
dic_msg[client_msg[cid]].append(msg) # 回复
server.sendto('收到了'.encode('utf-8'),addr)
print('消息字典:%s'%(dict(dic_msg)))
except Exception as e:
print(e)
Server端
# -*- coding:utf-8 -*-
import socket client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1',9002)
cid = ''
while 1:
try:
msg = input('>>>:').strip()
# 发送 cid跟消息用|分割开来——具体怎么做看具体需求
send_msg= cid+'|'+msg
client.sendto(send_msg.encode('utf-8'),server_addr)
# 接收
content = client.recv(1024).decode('utf-8')
print('server端回复:',content)
except Exception as e:
print(e)
break
Client端
实现效果如下:

三、基于并发的TCP实现
socketsever模块为我们提供了并发的功能,我们这里直接用socketsever模块做。
另外我们考虑到TCP的粘包问题,以Client端给Server端发送数据为例:我们需要先给Server端发送一个带有”信息“的字典。这里的信息可以是我们将要发送的数据的大小,也可以是其他的必要的数据,这里我们给Server端发送Client端的标识cid以及将要发送的数据的大小。
同时考虑到程序的解耦,我们把包含重要信息字典的处理放在pro_trance.py文件中,两端在收发信息的时候直接import即可。里面的代码为:
# -*- coding:utf-8 -*-
import json
import struct def pro_send(sk,dic,pro=True):
str_dic = json.dumps(dic)
bytes_dic = str_dic.encode('utf-8')
# 默认选择协议发送
if pro:
num_dic = struct.pack('i',len(bytes_dic))
sk.sendall(num_dic)
sk.sendall(bytes_dic) def pro_recv(sk,pro=True):
# 依据协议先收到的是字典的长度
if pro:
num_dic = sk.recv(4)
# 注意unpack得到的是一个元组,需要加上0索引取值
num = struct.unpack('i',num_dic)[0]
str_dic = sk.recv(num).decode('utf-8')
dic = json.loads(str_dic)
# 不根据协议接收直接用1024大小的长度来接收
else:
dic = json.loads(sk.recv(1024).decode('utf-8'))
return dic
pro_trance.py
接下来是Client端与Sever端的代码,这里模拟不同标识的客户端能够同时访问Server端的情况:
# -*- coding:utf-8 -*-
import socket from pro_trance import pro_send,pro_recv cid = ''
client = socket.socket()
client.connect(('127.0.0.1',9003))
while 1:
# 这里用msg模拟长数据,所以选择避免粘包的发送方式
msg = input('>>>:').strip()
bytes_msg = msg.encode('utf-8')
len_by_msg = len(bytes_msg)
dic = {'cid':cid,'data_size':len_by_msg}
# 协议发送携带信息的字典
pro_send(client,dic)
# 再发送数据
client.sendall(bytes_msg)
# 接收 —— 直接收 实际是否考虑粘包视具体设计而定
str_recv = client.recv(1024).decode('utf-8')
print('server reply:',str_recv)
Client1端
# -*- coding:utf-8 -*-
import socket from pro_trance import pro_send,pro_recv cid = ''
client = socket.socket()
client.connect(('127.0.0.1',9003))
while 1:
# 这里用msg模拟长数据,所以选择避免粘包的发送方式
msg = input('>>>:').strip()
bytes_msg = msg.encode('utf-8')
len_by_msg = len(bytes_msg)
dic = {'cid':cid,'data_size':len_by_msg}
# 协议发送携带信息的字典
pro_send(client,dic)
# 再发送数据
client.sendall(bytes_msg)
# 接收 —— 直接收 实际是否考虑粘包视具体设计而定
str_recv = client.recv(1024).decode('utf-8')
print('server reply:',str_recv)
Client2端
# -*- coding:utf-8 -*-
import socketserver
from collections import defaultdict from pro_trance import pro_send,pro_recv # 一般这种数据都是放在settings文件中的
client_msg = {
'':'Naruto',
'':'Sasuke',
} class Server(socketserver.BaseRequestHandler):
def handle(self):
dic_msg = defaultdict(list)
while 1:
# 根据协议接收信息字典
dic = pro_recv(self.request)
# client端的id
cid = dic['cid']
data_size = dic['data_size']
# 根据数据的长度接收
msg = self.request.recv(data_size).decode('utf-8')
# 利用之前的默认字典构建数据
dic_msg[client_msg[cid]]
dic_msg[client_msg[cid]].append(msg)
print('client %s,message:%s' % (client_msg[cid], dict(dic_msg)))
# 回复
self.request.sendall('received successfully!'.encode('utf-8'))
## 注意socketserver这里不用加close方法
## BaseRequestHandler有一个finish的相关的方法 if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1',9003),Server)
server.serve_forever()
Server端
演示效果如下:

在socket的server端处理client端发来的数据的更多相关文章
- 用同一台PC的两个网口实现Iperf的server端和client端
用同一台PC的两个网口实现Iperf的server端和client端 2015年10月20日 20:35:11 阅读数:2943 有时候需要发包,仅仅需要一定速率的流量,并不需要关心收到报文的大小,一 ...
- 【Tech】CAS多机部署Server和Java Client端
昨天尝试把cas的java client端部署到另外一台机器,结果就有问题了.(localhost部署cas server和java client端参见:http://www.cnblogs.com/ ...
- 微服务学习三:springboot与springcloud集成之Eurake的使用(server端,client端)
这个多亏了网站上的一个大神的博客: http://blog.csdn.net/forezp/article/details/70148833 强烈推荐学习: 1.springcloud是什么,这个大家 ...
- 使用gRPC搭建Server端与Client端
gRPC简介 gRPC是一种RPC框架技术,采用Protocal Buffers(协议缓存) 作为其接口定义的语言(就是Proto来写接口)和基础的消息交换格式. 在gRPC中,客户端应用程序可以直接 ...
- Spring Cloud config之三:config-server因为server端和client端的健康检查导致服务超时阻塞问题
springcloud线上一个问题,当config-server连不上git时,微服务集群慢慢的都挂掉. 在入口层增加了日志跟踪问题: org.springframework.cloud.config ...
- Socket编程实践(6) --TCP服务端注意事项
僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...
- Java Socket 连接 Client端 和 Server端
Client端: import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;i ...
- Linux下的C Socket编程 -- server端的简单示例
Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...
- Linux下的C Socket编程 -- 简介与client端的处理
Linux下的C Socket编程(一) 介绍 Socket是进程间通信的方式之一,是进程间的通信.这里说的进程并不一定是在同一台机器上也有可能是通过网络连接的不同机器上.只要他们之间建立起了sock ...
随机推荐
- JavaScript Node节点笔记
1. 节点及其类型: 1). 元素节点 2). 属性节点: 元素的属性, 可以直接通过属性的方式来操作. 3). 文本节点: 是元素节点的子节点, 其内容为文本. 2. 在 html 文档的什么位置编 ...
- 利用arcgis和envi对卫星图像按城市进行拼接,分割
1.首先在envi中打开多波段原素材,右键点击另存为TIFF,输入保存的路径将原素材转换为tif格式图片. 2.之后打开arcgis,导入全国地区界数据,点击工具栏中的筛选工具. 输入查找的范围以及匹 ...
- 学习笔记:分布式日志收集框架Flume
业务现状分析 WebServer/ApplicationServer分散在各个机器上,想在大数据平台hadoop上进行统计分析,就需要先把日志收集到hadoop平台上. 思考:如何解决我们的数据从其他 ...
- 田螺便利店—opencv3.4.5与vs2015配置并测试
参考博客:https://blog.csdn.net/sinat_39061823/article/details/80723096 遇到的问题:由于找不到 opencv_world345d.dll, ...
- react+umi+dva+antd中dva的数据流图解
- java-16习题
编写程序,产生10组彩票的“35选7”玩法的7个随机数.(-)随机数不能重复. 范围[,) import java.util.Iterator; import java.util.Random; im ...
- 软件开发者路线图梗概&书摘chapter6
安排你的课程:靠自己去寻求建议,安排课程 1.阅读列表:维护一张列表,更新未读和已读 保存在公共空间 得出模式.趋势.缺口,决定下一步,得到建议 参考书目形成优先级队列 从宽泛的读起,指导者推荐 能使 ...
- bat 传递参数
调用bat时,传递参数有个小问题,记录一下. 1.问题描述: 传递参数时,接收的值不对.传递了“1,2,3”,接收时,只剩下1.后面的没有了. 解决: 原因是bat取参时,语法弄错了. Syntax ...
- IPFS 探索
IPFS 探索 比特币当前是用于存金融交易数据,有leveldb 存关键小的交易数据.那么我们的文件,譬如一个网站里面的static file 怎么办? IPFS(InterPlanetary Fil ...
- 【Jest】笔记三:全局变量
一.前提 我们在使用unittest,testng框架的时候都知道,每个case都是项目独立的,上一个case返回的值是不能使用到下一个case的,但是实际中接口之间的关系是紧密相连的,这个时候我们怎 ...