day30

基于TCP协议的socket循环通信

server
import socket
phone = socket.socket()
phone.bind(("127.0.0.1", 8080))
phone.listen()
conn, addr = phone.accept() from_client_data = conn.recv(1024)
print(f"来自客户端的消息:{from_client_data.decode('utf-8')}") conn.close()
phone.close()
client
import socket
phone = socket.socket()
phone.connect(("127.0.0.1", 8080))
data = input("请输入>>>")
phone.send(data.encode("utf-8"))
phone.close()

基于TCP协议的socket 链接+循环 通信

代码功能:服务器不会断开,客户端可以断开(且不能输入空字符串)

server
import socket
phone = socket.socket()
phone.bind(("127.0.0.1", 8080))
phone.listen(3)
while 1:
conn, addr = phone.accept()
print(f"{addr}客户端连接了")
while 1:
try:
from_client_data = conn.recv(1024)
if from_client_data.decode("utf-8").upper() == "Q":
print(f"{addr}客户端通信关闭!")
break
else:
print(f"来自客户端的消息:{from_client_data.decode('utf-8')}")
while True:
data = input("请输入>>>")
if not data:
print("输入内容不为空!")
continue
else:
break
conn.send(data.encode("utf-8").upper())
except Exception:
print(f"{addr}客户端通信关闭!")
break
conn.close()
phone.close()
clicent
import socket
phone = socket.socket()
phone.connect(("127.0.0.1", 8080))
while 1:
try:
data = input("请输入>>>")
if not data:
print("输入内容不为空!")
continue
phone.send(data.encode("utf-8"))
if data.upper() == "Q":
print("通信关闭!")
break from_server_data = phone.recv(1024)
if from_server_data.decode("utf-8").upper() == "Q":
print("通信关闭!")
break
else:
print(f"来自服务器的消息:{from_server_data.decode('utf-8')}")
except Exception:
print("通信关闭!")
break
phone.close()

基于TCP协议的socket通信:实例:远程执行命令

bates:网络传输,文件存储时

server
import socket
phone = socket.socket()
phone.bind(("127.0.0.1", 8080))
phone.listen(3)
while 1:
conn, addr = phone.accept()
print(f"{addr}客户端连接了")
while 1:
try:
from_client_data = conn.recv(1024)
import subprocess
obj = subprocess.Popen(from_client_data.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
conn.send((obj.stdout.read() + obj.stderr.read()).upper())
except Exception:
print(f"{addr}客户端通信关闭!")
break
conn.close()
phone.close()
client
import socket
phone = socket.socket()
phone.connect(("127.0.0.1", 8080))
while 1:
try:
data = input("请输入>>>")
if not data:
print("输入内容不为空!")
continue
phone.send(data.encode("utf-8"))
if data.upper() == "Q":
print("通信关闭!")
break from_server_data = phone.recv(1024)
print(from_server_data.decode('gbk'))
except Exception:
print("通信关闭!")
break
phone.close()

粘包现象

为什么出现粘包?

只有TCP有粘包现象,UDP永远不会粘包!

操作系统的缓冲区

  • 为什么存在缓冲区

    • 暂时存储一些数据
    • 缓冲区存在如果你的网络波动,保证数据的收发稳定,匀速

缺点:造成了粘包现象之一

什么情况下出现粘包?

  • 出现粘包的情况

    • 客户端发送了一段数据过大,服务端只收了一部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包

    server

    # import socket
    # import subprocess
    # phone = socket.socket()
    # phone.bind(('127.0.0.1',8848))
    # phone.listen(2)
    # # listen: 2 允许有两个客户端加到半链接池,超过两个则会报错 # while 1:
    # conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
    # # print(f'链接来了: {conn,addr}')
    # while 1:
    # try:
    # from_client_data = conn.recv(1024) # 最多接受1024字节
    # if from_client_data.upper() == b'Q':
    # print('客户端正常退出聊天了')
    # break
    # obj = subprocess.Popen(from_client_data.decode('utf-8'),
    # shell=True,
    # stdout=subprocess.PIPE,
    # stderr=subprocess.PIPE,
    # )
    # result = obj.stdout.read() + obj.stderr.read()
    # print(f'总字节数:{len(result)}')
    # conn.send(result)
    # except ConnectionResetError:
    # print('客户端链接中断了')
    # break
    # conn.close()
    # phone.close()

    client

    # import socket
    #
    # phone = socket.socket()
    #
    # phone.connect(('127.0.0.1',8848))
    # while 1: # to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8') # if not to_server_data: # # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送 # print('发送内容不能为空') # continue # phone.send(to_server_data) # if to_server_data.upper() == b'Q': # break # from_server_data = phone.recv(300) # 最多接受1024字节 # # print(f'{from_server_data.decode("gbk")}') # print(len(from_server_data)) # phone.close()
    • 连续短暂的send多次(数据量很小),你的数据会统一发送出去

server

2. 连续短暂的send多次(数据量很小),你的数据会统一发送出去.
# import socket # phone = socket.socket() # # phone.bind(('127.0.0.1',8848)) # # phone.listen(5) #
# # conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中 # # from_client_data = conn.recv(1024) # 最多接受1024字节 # print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}') # conn.close() # phone.close()```python

client

  ```python
# 2. 连续短暂的send多次(数据量很小),你的数据会统一发送出去. # import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
#
#
# phone.send(b'he')
# phone.send(b'll')
# phone.send(b'o')
#
#
# phone.close()
# Nigle算法

深入研究收发

不一定是一收一发

  • 发多次收一次

server

# 发多次收一次
# import socket
# phone = socket.socket()
# phone.bind(('127.0.0.1',8848))
# phone.listen(5) # conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# from_client_data = conn.recv(1024) # 最多接受1024字节
# print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}') # conn.close()
# phone.close()

client

# 发多次收一次
import socket
phone = socket.socket()
phone.connect(('127.0.0.1',8848)) phone.send(b'he')
phone.send(b'llo')
phone.close()
Nigle算法
  • 发一次收多次

server

# 发一次收多次
# import socket
# phone = socket.socket()
# phone.bind(('127.0.0.1',8848))
# phone.listen(5) # conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}') # conn.close()
# phone.close()

client

# 发一次收多次
# import socket
# phone = socket.socket()
# phone.connect(('127.0.0.1',8848))
# phone.send(b'hello world')
# phone.close()

如何解决粘包现象

解决粘包现象的思路:

服务端发一次数据 10000字节

客户端接收数据时,循环接收,每次(至多)接收1024个字节,直至将所有的字节全部接收完毕,将接收的数据拼接在一起,最后解码

  • 遇到的问题1:recv的次数无法确定

    你发送总具体数据之前,先给我发一个总数据长度:5000个字节,如何在发送总数居

    客户端:先接收一个长度,5000个字节

    然后我再循环recv 控制循环的条件就是只要你接收的数据< 5000 一直接收

  • 遇到的问题2:总数据的长度转化成的字节数不固定

你要将total_size int类型转化成bytes类型才可以发送

387 ---- > str(387) '387' ---->bytes b'387' 长度 3bytes

4185 ----> str(4185) '4185' ---->bytes b'4185' 长度 4bytes

18000------------------------------------------------------> 长度 5bytes

我们要解决:

将不固定长度的int类型转化成固定长度的bytes并且还可以翻转回来

struct模块

服务端:
import struct
total_size = len(result)
print(f'总字节数:{total_size}')
head_bytes = struct.pack('i',total_size)
conn.send(head_bytes) conn.send(result)
total_size int类型 客户端:
head_bytes = phone.recv(4)
total_size = struct.unpack('i',head_bytes)[0]

low版解决粘包现象

server
import socket
import subprocess
import struct
phone = socket.socket()
phone.bind(("127.0.0.1", 8080))
phone.listen(3)
while 1:
conn, addr = phone.accept()
print(f"{addr}客户端连接了")
while 1:
try:
from_client_data = conn.recv(1024)
obj = subprocess.Popen(from_client_data.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
data = obj.stdout.read() + obj.stderr.read()
data_len = len(data)
print(f"长度:{len(data)}")
conn.send(struct.pack("i", data_len))
conn.send(data)
except Exception:
print(f"{addr}客户端通信关闭!")
break
conn.close()
phone.close()
client
import socket
import struct
phone = socket.socket()
phone.connect(("127.0.0.1", 8080))
while 1:
data = input("请输入>>>")
if not data:
print("输入内容不为空!")
continue
phone.send(data.encode("utf-8"))
if data.upper() == "Q":
print("通信关闭!")
break data_deposit = b""
data_head = phone.recv(4)
data_new = struct.unpack("i", data_head)[0]
while len(data_deposit) < data_new:
data_deposit += phone.recv(1024)
print(data_deposit.decode("gbk"))
phone.close()

day30——socket套接字(完全版)的更多相关文章

  1. 网络编程基础之Socket套接字简单应用

    一.Socket套接字实现通信循环 所谓通信循环,简单理解就是客户端可以给服务端循环发送信息并获得反馈的过程. 1.基础版 通信循环的程序分为两部分,即两个python模块,分别为客户端.py和服务端 ...

  2. 8.7 day28 网络编程 socket套接字 半连接池 通信循环 粘包问题 struct模块

    前置知识:不同计算机程序之间的数据传输 应用程序中的数据都是从程序所在计算机内存中读取的. 内存中的数据是从硬盘读取或者网络传输过来的 不同计算机程序数据传输需要经过七层协议物理连接介质才能到达目标程 ...

  3. 网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法

    TCP协议:传输协议,基于端口工作 三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立 ...

  4. Python socket套接字通信

    一.什么是socket? socket是一个模块, 又称套接字,用来封装 互联网协议(应用层以下的层). 二.为什么要有socket? socket可以实现互联网协议 应用层以下的层 的工作,提高开发 ...

  5. 网络编程与socket套接字

    网络编程与socket套接字 传输层 PORT协议 port是一种接口,数据通过它在计算机和其他设备(比如打印机,鼠标,键盘或监视器)之间,网络之间和其他直接连接的计算机之间传递 TCP协议 ​ 传输 ...

  6. java 25 - 3 网络编程之 Socket套接字

    Socket Socket套接字: 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字. Socket原理机制: 通信的两端都有Socket. 网络通信其实就是Socket ...

  7. 进程、线程、socket套接字-资源大小 & 切换代价

    另,进程 & 线程的很多知识可以看这里:http://www.cnblogs.com/charlesblc/p/6135666.html 今天查了一下进程和线程的资源占用. 比如问:栈和堆的大 ...

  8. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  9. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

随机推荐

  1. C++对象内存布局,this指针,对象作为参数,作为返回值

    class TestClass { public: void setNum(int num) { m_num1 = num; } int getNum() { return m_num1; } pri ...

  2. tox python项目虚拟环境管理自动化测试&&构建工具

    tox 是一个方便的工具,可以帮助我们管理python 的虚拟环境,同时可以进行项目自动测试以及构建 tox 如何工作的 说明 从上图我们也可以看出如何在我们项目中使用tox 参考资料 https:/ ...

  3. 19-ESP8266 SDK开发基础入门篇--C# TCP客户端编写 , 连接和断开

    https://www.cnblogs.com/yangfengwu/p/11130428.html 渐渐的看过去,,,好多节了... 这节做一个C# TCP客户端 新建项目啥子的就不详细截图写了,自 ...

  4. nginx配置ssl加密(单/双向认证、部分https)

    nginx下配置ssl本来是很简单的,无论是去认证中心买SSL安全证书还是自签署证书,但最近公司OA的一个需求,得以有个机会实际折腾一番.一开始采用的是全站加密,所有访问http:80的请求强制转换( ...

  5. 洛谷P2730 [IOI]魔板 Magic Squares

    题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜 ...

  6. Make sure you've included captcha.urls as explained in the INSTALLATION section on

    原因:django-simple-captcha将客户端编号与验证码默认存储在数据库中 解决办法: python manage.py migrate

  7. 在Windows环境下搭建Snort+BASE入侵检测系统

    操作系统: Windows 7 (service pack 1) 所需软件: 虚拟机:VirtualBox 网络数据包截取驱动程序:WinPcap 4.1.3 (WinPcap_4_1_3.exe) ...

  8. #C++初学记录(set进阶#acm cf 190802 B. Subsegments)

    B. Subsegments#set进阶 Programmer Sasha has recently begun to study data structures. His coach Stas to ...

  9. Linux 中 cp 命令(文件复制)

    cp命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录.它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下.cp命令还支持同时复制多个文件,当一次复制多个文件时,目标文 ...

  10. JAVA:使用栈实现一个队列

    使用栈实现一个队列,需要弄清楚栈和队列的区别: 栈:先进后出: 队列:先进先出. 实现思路: 1)通过两个栈(pushStack / popStack)对倒,确保 popStack 栈的出栈顺序与队列 ...