首页 > 编程语言 >Python基础37 基于tcp、udp套字编程、粘包现象、struct模块

Python基础37 基于tcp、udp套字编程、粘包现象、struct模块

时间:2023-07-04 21:00:19浏览次数:50  
标签:struct Python 37 server socket print data 服务端 客户端

基于tcp协议的套接字编程(sochet编程)

什么是socket?

  通常翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把tcp/ip层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中。

套接字分类:

AF_UNIX:用在局域网中

AF_INET:用在互联网中

客户端和服务端启动顺序

  先启动服务端,等待客户端来连接,然后接受客户端发来的消息,进行通讯

套接字工作流程

 简易版的套接字编程

服务端
import socket

# 实例化socket类
server = socket.socket()
# 服务端绑定信息
server.bind(('127.0.0.1', 8000))
# 监听消息、半连接池
server.listen(3)
# 代码停住,等待客户端发来消息
sock, addr = server.accept()
# 接收消息
data = sock.recv(1024)
print('客户端发来消息:%s' % data.decode())
# 回应客户端收到消息
sock.send(data)
# 断开与客户的联系
sock.close()
# 关机
server.close()



客户端
import socket

client = socket.socket()
# 与服务端建立连接
client.connect(('127.0.0.1', 8000))
# 输入发送信息
inp = input('请输入你要发送的信息:')
# 发送信息
client.send(inp.encode('utf8'))
# 接收服务端发来信息
data = client.recv(1024)
print('服务端发来:%s' % data.decode())
# 关闭连接
client.close()

加上通讯循环

服务端
import socket

# 实例化socket类
server = socket.socket()
# 服务端绑定信息
server.bind(('127.0.0.1', 8001))
# 监听消息、半连接池
server.listen(3)
# 代码停住,等待客户端发来消息
while True:
    sock, addr = server.accept()
    # 接收消息
    data = sock.recv(1024)
    print('客户端发来消息:%s' % data.decode())
    # 回应客户端收到消息
    sock.send(data)
    # 断开与客户的联系
    sock.close()
# 关机
server.close()



客户端
import socket

client = socket.socket()
# 与服务端建立连接
client.connect(('127.0.0.1', 8001))
# 输入发送信息
inp = input('请输入你要发送的信息:')
# 发送信息
client.send(inp.encode('utf8'))
# 接收服务端发来信息
data = client.recv(1024)
print('服务端发来:%s' % data.decode())
# 关闭连接
client.close()

加上连接循环

服务端
import socket

# 实例化socket类
server = socket.socket()
# 服务端绑定信息
server.bind(('127.0.0.1', 8012))
# 监听消息、半连接池
server.listen(3)
# 代码停住,等待客户端发来消息
while True:
    sock, addr = server.accept()  # 代码走到这里会停住,等待接收客户端发来的消息

    """
    sock:代表的是当前客户端的连接对象
    addr:代表的是客户端的信息(ip+port)
    """
    while True:
        try:
            # 5.真正的取到客户端发来的消息
            data = sock.recv(1024)  # 接收的最大数据,字节类型
            if len(data) == 0:
                break
            print("客户端发来的消息:%s" % data)
            # 6. 服务端个客户端发消息
            sock.send(data.upper())  # 数据类型必须是字节类型
        except ConnectionResetError as e:
            print(e)
            break
    # 7. 断开与客户端之间的连接
    sock.close()
# 8. 关机
server.close()



客户端
import socket

client = socket.socket()
# 与服务端建立连接
client.connect(('127.0.0.1', 8012))
# 输入发送信息
while True:
    inp = input('请输入你要发送的信息:')
    if inp == 'q':
        break
    if len(inp) == 0:
        continue
    # 发送信息
    client.send(inp.encode('utf8'))
    # 接收服务端发来信息
    data = client.recv(1024)
    print('服务端发来:%s' % data.decode())

基于UDP协议的套接字编程

服务端

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8202))
while True:
    data, addr = server.recvfrom(1024)
    print('接收到客户端信息》》》:%s、%s' % (data.decode(), addr))
    server.sendto(data, addr)

server.close()


客户端
import socket

client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 数据报协议-》UDP

while True:
    msg = input('>>: ').strip()
    if msg == 'q':
        break
    if msg == '':
        continue
    client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8202))
    data, server_addr = client.recvfrom(1024)
    print(data.decode())

client.close()

粘包现象

其实就是网络·传输里面的数据没有被完全取出来

TCP的特性:流式协议
  当客户端发送的数据量很小并且时间间隔很小的时候
  它会把数据打包成一个包一次性发送

发生粘包两种情况

1.发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

服务端

from socket import *
ip_port=('127.0.0.1',8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)


conn,addr=tcp_socket_server.accept()


data1=conn.recv(10)
data2=conn.recv(10)

print('----->',data1.decode('utf-8'))
print('----->',data2.decode('utf-8'))

conn.close()

客户端

import socket
BUFSIZE=1024
ip_port=('127.0.0.1',8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)


s.send('hello'.encode('utf-8'))
s.send('feng'.encode('utf-8'))

2.接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

服务端

from socket import *
ip_port=('127.0.0.1',8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)


conn,addr=tcp_socket_server.accept()


data1=conn.recv(2) #一次没有收完整
data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的

print('----->',data1.decode('utf-8'))
print('----->',data2.decode('utf-8'))

conn.close()

客户端'

import socket
BUFSIZE=1024
ip_port=('127.0.0.1',8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)


s.send('hello feng'.encode('utf-8'))

拆包的发生情况

  当发送端缓冲区的长度大于网卡的MTU(网络能够传输的最大数据包大小,以字节为单位)时,tcp会将这次发送的数据拆成几个数据包发送出去

解决粘包问题

 

struct模块

#_*_coding:utf-8_*_
#http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html
__author__ = 'ly'
import struct
import binascii
import ctypes

values1 = (1, 'abc'.encode('utf-8'), 2.7)
values2 = ('defg'.encode('utf-8'),101)
s1 = struct.Struct('I3sf')
s2 = struct.Struct('4sI')

print(s1.size,s2.size)
prebuffer=ctypes.create_string_buffer(s1.size+s2.size)
print('Before : ',binascii.hexlify(prebuffer))
# t=binascii.hexlify('asdfaf'.encode('utf-8'))
# print(t)


s1.pack_into(prebuffer,0,*values1)
s2.pack_into(prebuffer,s1.size,*values2)

print('After pack',binascii.hexlify(prebuffer))
print(s1.unpack_from(prebuffer,0))
print(s2.unpack_from(prebuffer,s1.size))

s3=struct.Struct('ii')
s3.pack_into(prebuffer,0,123,123)
print('After pack',binascii.hexlify(prebuffer))
print(s3.unpack_from(prebuffer,0))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

标签:struct,Python,37,server,socket,print,data,服务端,客户端
From: https://www.cnblogs.com/shanghaipudong/p/17526205.html

相关文章

  • python给多页excel工作表写跳转目录及回转链接
    1fromopenpyxlimportload_workbook2#fromopenpyxl.drawing.textimportParagraph,RegularTextRun3fromopenpyxl.worksheet.hyperlinkimportHyperlink4#fromopenpyxl.utilsimportget_column_letter56#打开现有的工作簿7workbook=load_workbo......
  • python之pip
    #####################   查看当前环境已经安装了哪些包:piplist   查看安装包详情  安装pip_search    使用pip_search           ########################......
  • python索引
    变量名[]正向数时是从零开始,反向是从-1开始切片变量[头下标:尾下标](不包括尾下标所代表的字符)变量名[:]:不指定头下标和尾下标时代表获取整个字符串变量名[1:]:不指定尾下标时代表从指定的头下标到末尾变量名[:5]:不指定头下标时代表从头开始到尾下标指定的字符但不包含尾下标所......
  • python网络编程 socket
    基于TCP协议的套接字编程(socket编程)什么是Socket呢?我们经常把Socket翻译为套接字,Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。套接字的分类:AF_UNIX:用在局域网中AF_INET:用在互联网中"""客户端和......
  • 为组态王编写的 时间段 选择 控件 python
    日历控件使用说明这是一个专门为组态软件(如组态王,力控等)设计的时间选择控件,用于选择一个时间段,来进行数据报表的查询.控件实际由2部分组成,1个UI程序,和1个modbusTCP从机服务器.从机服务器用于UI程序和组态软件的通信.  日期部分,时间间隔部分,支持滚轮改变日期......
  • Python | yield关键字详解
    yield关键字的说明yield是Python中的一个关键字,它通常与生成器函数一起使用。yield就是保存当前程序执行状态。你用for循环的时候,每次取一个元素的时候就会计算一次。用yield的函数叫generator,和iterator一样,它的好处是不用一次计算所有元素,而是用一次算一次,可以节省......
  • python函数外变量传到函数内处理后不改变函数外的变量,copy模块使用
    线上代码a=[1,2,3]defabc(a):a.remove(1)abc(a)print(a)这段代码先指定了一个a变量是个list,又写了一个abc函数,功能是把外面传进来的list里面的1这个值去掉按理说在函数内的执行只应该属于函数内的变化,但是实际打印结果是[2,3],函数把外面变量的1删掉了这不是我想要......
  • python接口自动化封装导出excel方法和读写excel数据
    一、首先需要思考,我们在页面导出excel,用python导出如何写入文件的封装前需要确认python导出excel接口返回的是一个什么样的数据类型如下:我们先看下不对返回结果做处理,直接接收数据类型是一个对象,无法获取返回值此时我们需要对返回数据做处理,如下;response.text#响应文本数据......
  • Python 元组转换为列表
    1.直接将元组转为列表tup=(21,19,11,46,18)print(tup)lt=list(tup)print(lt)输出(21,19,11,46,18)[21,19,11,46,18]2.将元组列表转为列表#Listoftupleinitializationlistoftuples=[("Apple",1),("Microsoft",2),("Amazon",......
  • python计算某字符出现次数
    count()方法用于统计字符串里某个字符或子字符串出现的次数.st1=input().upper()st2=input().upper()print(st1.count(st2))tips:只要将所有字符串统一转化为大写或者小写,计算次数即可。upper()全部转化为大写lower()全部转化为小写另:str.count(sub,start=0,en......