一、楔子

  最近做了一个需求遇到一个坑,归结成一个小问题,其实就是在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端发来的数据的更多相关文章

  1. 用同一台PC的两个网口实现Iperf的server端和client端

    用同一台PC的两个网口实现Iperf的server端和client端 2015年10月20日 20:35:11 阅读数:2943 有时候需要发包,仅仅需要一定速率的流量,并不需要关心收到报文的大小,一 ...

  2. 【Tech】CAS多机部署Server和Java Client端

    昨天尝试把cas的java client端部署到另外一台机器,结果就有问题了.(localhost部署cas server和java client端参见:http://www.cnblogs.com/ ...

  3. 微服务学习三:springboot与springcloud集成之Eurake的使用(server端,client端)

    这个多亏了网站上的一个大神的博客: http://blog.csdn.net/forezp/article/details/70148833 强烈推荐学习: 1.springcloud是什么,这个大家 ...

  4. 使用gRPC搭建Server端与Client端

    gRPC简介 gRPC是一种RPC框架技术,采用Protocal Buffers(协议缓存) 作为其接口定义的语言(就是Proto来写接口)和基础的消息交换格式. 在gRPC中,客户端应用程序可以直接 ...

  5. Spring Cloud config之三:config-server因为server端和client端的健康检查导致服务超时阻塞问题

    springcloud线上一个问题,当config-server连不上git时,微服务集群慢慢的都挂掉. 在入口层增加了日志跟踪问题: org.springframework.cloud.config ...

  6. Socket编程实践(6) --TCP服务端注意事项

    僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...

  7. Java Socket 连接 Client端 和 Server端

    Client端: import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;i ...

  8. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  9. Linux下的C Socket编程 -- 简介与client端的处理

    Linux下的C Socket编程(一) 介绍 Socket是进程间通信的方式之一,是进程间的通信.这里说的进程并不一定是在同一台机器上也有可能是通过网络连接的不同机器上.只要他们之间建立起了sock ...

随机推荐

  1. 解决npm ERR! Please try running this command again as root/Administrator. 问题

    win10下,使用npm 安装插件时报npm ERR! Please try running this command again as root/Administrator的错误, 解决方案:需要删 ...

  2. 如何用core自动创建model,与数据库连接

    打开vs.点击视图->其他->程序包管理器控制台->选择默认项目->输入 Scaffold-DbContext “Data Source=XXX;Initial Catalog ...

  3. linux 中 nginx配置

    1.nginx中include的使用 在/usr/local/nginx/conf/nginx.conf中可以使用include去加载其他配置文件: 例如:include vhost/*.conf; ...

  4. aiohttp AppRunner的用法

    参考廖雪峰的aiohttp教程,会出现两个DeprecationWarning, loop argument is deprecated Application.make_handler(...) i ...

  5. ubuntu18.04LTS配置apache虚拟目录(基于端口)

    假设在用户目录下要新建两个虚拟目录web1,web2,分别对应端口8081,8082 $ cd ~ #切换到用户目录 $ mkdir www #新建www文件夹,以后新建的虚拟目录都放在该文件夹下 $ ...

  6. webbug3.0靶场第二关

    由于是新手,当看见一个图片后一脸蒙比,查了一下才知道这原来叫做隐写术 看人家说破解图片隐写术用Stegsolve非常好用,然后查了一下kali软件仓库并没有找到Steegsolve这个软件,只能另想他 ...

  7. socket端口绑定后通过bat干掉

    @echo off::port为需要去绑定端口set port=8888for /f "tokens=5 delims= " %%a in ('netstat -ano ^|fin ...

  8. vpdn1

    在使用L2TP协议构建的VPDN典型组网中,包含LAC和LNS两部分. 1.LAC LAC表示L2TP访问集中器(L2TP Access Concentrator),是附属在交换网络上的具有PPP端系 ...

  9. 赋值,什么时候用value,什么时候用innerText

    赋值语句: window.document.getElementById('limittime').value='${date}' window.document.getElementById('li ...

  10. 经典问题----最小生成树(prim普里姆贪心算法)

    题目简述:假如有一个无向连通图,有n个顶点,有许多(带有权值即长度)边,让你用在其中选n-1条边把这n个顶点连起来,不漏掉任何一个点,然后这n-1条边的权值总和最小,就是最小生成树了,注意,不可绕成圈 ...