socket套接字编程

套接字介绍:

1.套接字:实现网络编程进行数据传输的一种技术手段

2.Python实现套接字编程: import socket

3.套接字分类

1. 流式套接字(SOCK_STREAM):提供面向连接的、可靠的数据传输服务,通常用于TCP协议。(面向连接--tcp协议--可靠的--流式套接字)


2. 数据报套接字(SOCK_DGRAM):提供无连接的、不可靠的数据传输服务,通常用于UDP协议。(无连接--udp协议--不可靠--流式套接字)


3. 原始套接字(SOCK_RAW):允许直接访问网络层数据包,通常用于实现自定义的网络协议或进行网络数据包的捕获和分析。


4. 顺序数据包套接字(SOCK_SEQPACKET):提供面向连接的、可靠的数据传输服务,但保证数据的顺序传递。


5. 数据报文套接字(SOCK_RDM):提供面向连接的、可靠的数据传输服务,但不保证数据的顺序传递。

TCP套接字编程 

socket套接字编程_第1张图片

服务端流程

                socket  -->  bind --> listen --> accpet  -->send/recv --> close

代码实现

import socket
# 1 创建套接字
socketd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#  共能:创建套接字
#  参数: socket_family 网络地址类型 AF_INET表示ipv4
#        socket_type 套接字类型 SOCK_STREAM(流式)  SOCK_DGRAM(数据报)
#        proto  选择子协议
#  返回值 套接字对象

# 2  绑定地址
# 本地地址: ‘localhost’, '127.0.0.1'
# 网络地址: ‘172.x......’
# 自动获取地址: ‘0.0.0.0
addr = ('0.0.0.0', 8000)
socketd.bind(addr)
# 功能:绑定本机网络地址
# 参数:二元元组(IP,port)


# 3 设置监听
n = 3
socketd.listen(n)
# 功能: 将套接字设置为监听套接字,确认监听队列大小,可以连接多个客户端,但是连接的过程是一个一个连接的
# 参数: 监听队列大小


# 4 等待处理客户端连接请求
connect, add = socketd.accept()  # 阻塞函数
# 功能: 阻塞等待处理客户端请求
# 返回值: connect  客户端连接套接字
#        add  连接的客户端地址


# 5 收发消息
data = connect.recv(1024)
# 功能: 接收客户端的消息
# 参数: 每次接收消息的最大的大小
# 返回值: 接收的内容,该返回值的类型是字节串(bytes格式)

msg = 'Hello World!'
n = connect.send(msg.encode())
# 功能: 发送消息
# 参数: 发送的内容 (bytes格式)
# 返回值: 发送的字节数

# 6 关闭套接字
socketd.close()
# 功能: 关闭套接字

socket套接字编程_第2张图片

                                                       (绑定地址可以参考上图 )

客户端流程

                socket --> bind(可选) --> connect --> send/recv --> close

代码实现

import socket
# 1 创建套接字
socketd = socket.socket()


# 2 连接
addr = ('127.0.0.1', 8000)
socketd.connect(addr)

# 收发消息
data = 'Hello! what is your name?'
socketd.send(data.encode())

msg = socketd.recv(1024)

# 关闭套接字
socketd.close()

 简单的聊天实现

服务端

import socket

socketd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

addr = ('0.0.0.0', 8000)
socketd.bind(addr)

n = 3
socketd.listen(n)

print('waiting for connect...')
while True:
    connect, add = socketd.accept()  # 阻塞函数,等待客户端连接
    print('connect from {}'.format(add))
    while True:
        data = connect.recv(1024)
        if not data:  # r如果data为空的话,说明客户端已经退出
            break
        print(data.decode())
        msg = 'my name is zjc'
        n = connect.send(msg.encode())
    connect.close()  # 关闭该客户端的连接
    print('waiting new connect...')  # 等待新的客户端连接
socketd.close()

客户端

import socket
# 1 创建套接字
socketd = socket.socket()


# 2 连接
addr = ('127.0.0.1', 8000)
socketd.connect(addr)
while True:
    # 收发消息
    data = input('请输入...')
    if not data:  # 如果用户未输入,则判断用户已经退出
        break
    socketd.send(data.encode())  # 发送消息
    msg = socketd.recv(1024)  # 接收消息
    print(msg.decode())

# 关闭套接字
socketd.close()

 收发缓冲区

概念

TCP套接字有两种缓冲区:发送缓冲区接收缓冲区

发送缓冲区:数据从应用程序发送到套接字时,首先被放入发送缓冲区。如果发送缓冲区已满,应用程序可能会被阻塞,直到有空间可用。发送缓冲区的大小可以通过操作系统的参数进行调整。

接收缓冲区:当套接字接收到数据时,数据首先被放入接收缓冲区。如果接收缓冲区已满,新的数据可能会被丢弃。接收缓冲区的大小同样可以通过操作系统的参数进行调整。

功能

1.网络缓冲区有效的协调了消息的收发速度

2.send和recv实际上是向缓冲区发送接收消息,当缓冲区不为空时recv就不会阻塞。

TCP粘包

概念

TCP粘包是指发送方发送的若干包数据到接收方时,接收方可能会将多个数据包粘合在一起,导致接收方无法正确解析每个数据包的边界。这可能会导致接收方无法正确处理数据,从而产生错误。

原因 


1. TCP是面向流的协议,发送的数据被看作是一个字节流,而不是一个个独立的数据包。因此,在接收端无法直接得知发送端发送的数据包的边界。
2. 网络传输时,数据包的大小可能会受到MTU(最大传输单元)的限制,导致大的数据包被分割成多个小的数据包,而接收端可能会一次性接收到多个小的数据包。

解决方法


1. 使用固定长度的消息。发送端在每个数据包的末尾添加固定长度的填充数据,接收端按照固定长度来切分数据包。
2. 使用特殊的分隔符。发送端在每个数据包的末尾添加特殊的分隔符,接收端根据分隔符来切分数据包。
3. 使用消息头来表示消息的长度。发送端在每个数据包的开头添加消息长度信息,接收端先读取消息长度,然后按照消息长度来接收完整的数据包。

接收发送文件练习

服务端

import socket

sockedf = socket.socket()

sockedf.bind(('0.0.0.0', 8000))

sockedf.listen(3)
while True:
    # 等待客户端连接
    print('Waiting for connect...')
    connect, add = sockedf.accept()
    f = open('gg.jpg', 'wb')
    while True:
            data = connect.recv(1024)  # 接收消息
            if not data:
                break
            f.write(data)
    connect.close()
    f.close()

sockedf.close()

客户端

import socket

sockedf = socket.socket()

sockedf.connect(('127.0.0.1',8000))
f = open('ojbk.jpg', 'rb')
while True:
    data = f.read(1024)
    if not data:
        break
    sockedf.send(data)
f.close()
sockedf.close()

你可能感兴趣的:(计算机网络,Python,服务器,linux)