复习下socket 编程的步骤:

服务端:
 
1 声明socket 实例
server = socket.socket()  #括号里不写  默认地址簇使用AF_INET  即 IPv4       默认type 为 sock.SOCK_STREAM 即 TCP/IP 协议   
2 绑定IP地址和端口
server.bind(('localhost',9999))  #ip地址和端口  元组形式 ,端口为整数形式
 
3 开始监听
server.listen()
 
4 进入阻塞状态,等待连接进入
######## 从这里开始可以加入循环,循环不同的连接 ,这样就可以接受不同的客户端的连接了#####
#while True:
 
  # 获取客户端ip地址和端口  开启一个连接实例
 
 
##############  从这里开始循环,这样就可以循环收到客户端数据,但是只收这一个客户端 ###########
##客户端一断开,conn收到的就全为空数据,这样就进入了一个死循环,所以需要一个if 判断
#while True:
5 收数据
data = conn.recv(1024)  #接收最大数据量, 官方建议最大8192  写整数据
# 这里加入if 判断
# if not data:
#    break
print(data)
 
6 可以往回发送数据
conn.send(data.upper()) #可以发送任何数据,这里把收到的变为大写
 
7 server.close()
 
  
客户端:
1 声明socket 实例:
client= socket.socket()
2 连接服务端:
client.connect(('server_ip',9999))   #连接服务端的ip及端口 元组形式 ,端口为整数形式
3 发数据
client.send(data)   #发送数据,任意数据
# 4 收取服务端返回的数据
#   recv_data = client.recv(1024)

动态导入模块:

 实践:
1 lib下的aa
def test():
print("hehe")
class C(object):
name = "yang"
def __init__(self):
self.name = 'shenyang' lib外的test
import importlib
dd = importlib.import_module('lib.aa')
dd.test()
print(dd.C().name)

运行:

断言:
判断类型
 
正确判断

判断错误

和 if  判断  一样 但是更简洁,一句话就OK

继续socket 编程:

客户端虽然写的是收1024  但是不一定收到1024  只代表最多收到1024  即使服务端返回100个字节 也收
 
客户端收完数据,收多少 要服务端先发一个要发多少的数据,客户端收到后,开始接收数据,直到收到指定大小的数据为止,不再接收
实践:
服务端
 #!/usr/bin/env python3
# Author: Shen Yang
import socket,os
ip_address = '192.168.16.10'
port = 8888
bind_address = (ip_address,port)
server = socket.socket()
server.bind(bind_address)
server.listen()
while True:
conn,addr = server.accept()
while True:
data = conn.recv(1024).decode()
if not data:
print("丢失连接")
break
print("这是来自",addr,data)
cmd_res = os.popen(data).read()
conn.send(str(len(cmd_res.encode('utf-8'))).encode('utf-8'))
conn.send(cmd_res.encode('utf-8'))
server.close()

客户端

 #!/usr/bin/env python3
# Author: Shen Yang
import socket
ip_address = '192.168.16.10'
# ip_address = '192.168.81.133'
port = 8888
conn_address = (ip_address,port)
client = socket.socket()
client.connect(conn_address)
while True:
cmd = input(":> ").encode('utf-8')
if len(cmd) == 0:
continue
client.send(cmd)
cmd_size = int(client.recv(1024).decode())
print(cmd_size)
recov_size = 0
recov_data = b''
while recov_size < cmd_size:
data = client.recv(1024)
#print(data)
recov_size += len(data)
#print(recov_size)
recov_data += data
else:
print("收完了,大小",recov_size)
print(recov_data.decode())
client.close()

上面的代码 在linux 发送 会出现粘包   客户端收到的是两个数据

终极解决办法:
 
服务端添加接收过程:

客户端加发送过程:

实践:
ssh_server:
#!/usr/bin/env python3
import socket,os
ip_address = '192.168.81.133'
port = 8888
bind_address = (ip_address,port)
server = socket.socket()
server.bind(bind_address)
server.listen()
while True:
conn,addr = server.accept()
while True:
data = conn.recv(1024).decode()
if not data:
print("丢失连接")
break
print("这是来自",addr,data)
cmd_res = os.popen(data).read()
conn.send(str(len(cmd_res.encode('utf-8'))).encode('utf-8'))
ack = conn.recv(1024).decode()
print(ack)
conn.send(cmd_res.encode('utf-8'))
server.close()

ssh_client

 #!/usr/bin/env python3
import socket
ip_address = '192.168.81.133'
port = 8888
conn_address = (ip_address,port)
client = socket.socket()
client.connect(conn_address)
while True:
cmd = input(":> ").encode('utf-8')
if len(cmd) == 0:
continue
client.send(cmd)
cmd_size = int(client.recv(1024).decode())
print(cmd_size)
client.send("收到大小".encode('utf-8'))
recov_size = 0
recov_data = b''
while recov_size < cmd_size:
data = client.recv(1024)
#print(data)
recov_size += len(data)
#print(recov_size)
recov_data += data
else:
print("收完了,大小",recov_size)
print(recov_data.decode())
client.close()

传文件:
 
server 端逻辑:

使用 os.stat  获取文件详细信息,发送给客户端

另外一个解决粘包的方法:

只收指定大小的数据  永远不可能粘包

实践:
 ftp_server.py
 #!/usr/bin/env python3
import socket,os,hashlib
ip_address = '192.168.81.133'
port = 8888
bind_address = (ip_address,port)
server = socket.socket()
server.bind(bind_address)
server.listen()
while True:
conn,addr = server.accept()
while True:
print("等待新链接")
data = conn.recv(1024)
if not data:
print("丢失连接")
break
print("这是来自",addr,data)
cmd,file_name = data.decode().split()
if os.path.isfile(file_name):
m = hashlib.md5()
f = open(file_name,'rb')
file_size = os.stat(file_name).st_size
conn.send(str(file_size).encode())
ack = conn.recv(1024).decode()
print("确认:",ack)
for line in f:
m.update(line)
print("sending...")
conn.send(line)
f.close()
conn.send(m.hexdigest().encode())
print("发送完毕")
server.close()

ftp_client.py

 #!/usr/bin/env python3
import socket,hashlib
ip_address = '192.168.81.133'
port = 8888
conn_address = (ip_address,port)
client = socket.socket()
client.connect(conn_address)
while True:
cmd = input("input your cmd:> ").strip()
if len(cmd) == 0:
continue
if cmd.startswith("get"):
client.send(cmd.encode('utf-8'))
file_name = cmd.split()[1]
server_response = client.recv(1024)
print("收到回应:",server_response)
client.send("收到".encode('utf-8'))
total_file_size = int(server_response.decode())
print("总的",total_file_size)
f = open(file_name + '.new','wb')
recov_file_size = 0
m = hashlib.md5()
while recov_file_size < total_file_size:
if total_file_size - recov_file_size > 1024:
size = 1024
else:
size = total_file_size - recov_file_size
print("最后收",size)
#print("收数据...")
data = client.recv(size)
m.update(data)
recov_file_size += len(data)
f.write(data)
else:
print("收完了,大小",recov_file_size,total_file_size)
f.close()
print("服务器端发送的原MD5",client.recv(1024).decode())
print("自己算出来的最终MD5",m.hexdigest())
client.close()

开始学习SocketSever
 
SocketSever  是对socket 的再封装
 
最常用的是 TCP 和 UDP 

继承关系:

创建socket server 步骤:

下面是重写的handle:

跟客户端所有的交互都是在handle 里处理的
每一个客户端请求都是实例化一个handle
继续修改handle
增加循环:
并增加判断客户端退出:

实践:
server:
 import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
self.data = self.request.recv(1024).strip()
print("来自",self.client_address)
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("客户端退出",e)
break
if __name__ == "__main__":
HOST,PORT="localhost",9999
server = socketserver.TCPServer((HOST,PORT),MyTCPHandler)
server.serve_forever()

client:

 import  socket
client = socket.socket() #声明socket类型,同时生成socket连接对象
#client.connect(('192.168.16.200',9999))
client.connect(('localhost',9999))
while True:
msg = input(">>:").strip()
if len(msg) == 0:continue
client.send(msg.encode("utf-8"))
data = client.recv(10240)
print("recv:",data.decode())
client.close()

上面的并不支持多并发
到现在为止,只是写了一个一对一的服务器
下面写入多并发:
只改一个地方:
1 使用多线程 来实现

2 使用多进程实现:  (windos 下不行,不支持,但是linux  绝得好使)

 
 

介绍 socketserver的一些方法:
 
1 返回文件描述符  (系统自己调用,我们一般用不到)

2 处理单个请求,一般也用不到

3 一直收请求,直到收到一个明确的shutdown   (每0.5秒检测是否给我发了shutdown 的信号)

收到shutdown 后调用 service_action() 清理垃圾僵尸进程

4 告诉 server_forever() 关闭

5 地址的重用,不需要等待tcp断开

普通的sock server
server = socket.socket() #获得socket实例
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  #重用地址
请求的三个过程,都可以自定义:
1 setup
2 handle
3 finish

day08 多线程socket 编程,tcp粘包处理的更多相关文章

  1. socket编程 TCP 粘包和半包 的问题及解决办法

    一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系. 粘包 为x.5个包 半包 为0.5个包 由于网络原因 一次 ...

  2. Socket编程--TCP粘包问题

    TCP是个流协议,它存在粘包问题 产生粘包的原因是: TCP所传输的报文段有MSS的限制,如果套接字缓冲区的大小大于MSS,也会导致消息的分割发送. 由于链路层最大发送单元MTU,在IP层会进行数据的 ...

  3. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  4. Python全栈-网络编程-TCP粘包

    一.什么是TCP粘包 C/S架构下,接收方不知道每个消息的发送间隙.也不知道每次应该提取多少个字节的数据,与此同时,TCP是面向连接的,面向流的,收发两端都要有,因此发送端为了将多个发往接收端的数据包 ...

  5. socket编程解决粘包和丢包问题

    ##socket 丢包粘包解决方式 采用固定头部长度(一般为4个字节),包头保存的是包体的长度 header+body 包头+包体 下面的例子不是按照上图中规定的格式编写的,但是思路都是一样的,先读出 ...

  6. Socket编程 Tcp和粘包

    大多数程序员都要接触网络编程,Web开发天天和http打交道.稍微底层一点的程序员,就是TCP/UDP . 对程序员来说,Tcp/udp的核心是Socket编程. 我的浅薄的观点---------理解 ...

  7. Socket编程(4)TCP粘包问题及解决方案

    ① TCP是个流协议,它存在粘包问题 TCP是一个基于字节流的传输服务,"流"意味着TCP所传输的数据是没有边界的.这不同于UDP提供基于消息的传输服务,其传输的数据是有边界的.T ...

  8. Socket编程实践(5) --TCP粘包问题与解决

    TCP粘包问题 由于TCP协议是基于字节流且无边界的传输协议, 因此很有可能产生粘包问题, 问题描述如下 对于Host A 发送的M1与M2两个各10K的数据块, Host B 接收数据的方式不确定, ...

  9. 查漏补缺:socket编程:TCP粘包问题和常用解决方案(上)

    1.TCP粘包问题的产生(发送端) 由于TCP协议是基于字节流并且无边界的传输协议,因此很容易产生粘包问题.TCP的粘包可能发生在发送端,也可能发生在接收端.发送端的粘包是TCP协议本身引起的,TCP ...

随机推荐

  1. git-gui:使用终端打开以后出现错误提示 Spell checking is unavable

    参考链接:http://www.lai18.com/content/10706682.html 安装了git-gui,打开以后出现以下提示: Spell checking is unavable: e ...

  2. Garmin APP开发之布局

    上一章节介绍了garmin app开发的入门,包括garmin-sdk,开发工具的安装部署,文章结尾我们新建了我们的第一个app程序Garmin开发-入门: http://tieba.baidu.co ...

  3. Centos安装iptables防火墙

    一.安装说明: 1.因为centos7.0及以上版本就默认安装了firewall防火墙,但有时候根据项目实际所需,服务器上还是需要安装iptables,以下就是具体的安装步骤: 2.因阿里云在服务器外 ...

  4. SequenceFile和MapFile

    HDFS和MR主要针对大数据文件来设计,在小文件处理上效率低.解决方法是选择一个容器,将这些小文件包装起来,将整个文件作为一条记录,可以获取更高效率的储存和处理,避免多次打开关闭流耗费计算资源.hdf ...

  5. 《spss统计分析与行业应用案例详解》:实例十二 卡方检验

    卡方检验的功能与意义 SPSS的卡方检验是非参数检验方法的一种,其基本功能足通过样本的 频数分布来推断总体是否服从某种理论分布或某种假设分布,这种检验过程是通过分析实际的频数与理论的频数之间的差别或是 ...

  6. UVA1607 Gates 与非门电路 (二分)

    题意:给你一个按发生时间的序列,表示与非门电路的输入,一开始全部输入是x,现在要改成尽量少的x,实现相同的功能. 题解:电路功能只有4中0,1,x,非x.那么如果一开始x改变了,输出结果不变,那么说明 ...

  7. CDOJ 485 UESTC 485 Game (八数码变形,映射,逆cantor展开)

    题意:八数码,但是转移的方式是转动,一共十二种,有多组询问,初态唯一,终态不唯一. 题解:初态唯一,那么可以预处理出012345678的所有转移情况,然后将初态对012345678做一个映射,再枚举一 ...

  8. Spark Job调优(Part 2)

    原文链接:https://wongxingjun.github.io/2016/05/11/Spark-Job%E8%B0%83%E4%BC%98-Part-2/ 这篇文章将会完成Part 1中留下的 ...

  9. Problem D: 小平查密码

    Problem D: 小平查密码 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 194  Solved: 40[Submit][Status][Web ...

  10. python_92_面向对象初体验

    class dog: def __init__(self,name): self.name=name def bulk(self): print('%s汪汪汪!'%self.name) d1=dog( ...