socket套接字

时间:2022-08-05
本文章向大家介绍socket套接字,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

传输层

TCP协议

1.TCP也就是传输控制协议(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,用于规定数据传输所遵循的规则

2.三次握手
2.1客户端发送SYN报文给服务器端,进入SYN_SEND状态
2.2服务器端收到SYN报文,回应一个SYN、ACK报文,进入SYN_RECV状态
2.3客户端收到服务器端的SYN报文,回应一个ACK报文,进入Established状态
三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了

3.四次握手
3.1某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕
3.2接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认
3.3一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN
3.4接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节
'''
基于TCP传输数据非常的安全,不容易丢失,因为TCP有二次确认机制,每次发送数据后都需要返回确认消息,否则就会在一定的时间内反复发送
'''

UDP协议

1.UDP也就是用户数据报协议(User Datagram Protocol),UDP是支持一个无连接的传输协议,为应用程序提供了一种无需建立连接就可以发送封装的IP数据包的方法

2.UDP协议并不提供数据传送的保证机制,如果在从发送方到接收方的传递过程中出现数据包的丢失,协议本身并不能做出任何检测或提示,因此,通常人们把UDP协议称为不可靠的传输协议

'''
TCP:数据接收方收到发送方传来的信息时,会自动向发送方发出确认消息
发送方只有在接收到该确认消息之后才继续传送其它信息,否则将一直等待直到收到确认信息为止
UDP:如果在从发送方到接收方的传递过程中出现数据包的丢失,协议本身并不能做出任何检测或提示
'''

应用层

主要取决于程序员自己采用什么策略和协议
常见协议有:HTTP HTTPS FTP...

socket套接字

套接字使用

1.基于文件类型的套接字家族的名字:AF_UNIX
2.基于网络类型的套接字家族的名字:AF_INET

'运行程序的时候,肯定是先运行服务端,之后才运行客户端'

服务端
import socket
# 1.创建一个socket对象
server = socket.socket()  # 括号内什么都不写 默认就是基于网络的TCP套接字
# 2.绑定一个固定的地址(ip\port)
server.bind(('127.0.0.1', 8080))  # 127.0.0.1本地回环地址(只允许自己的机器访问)
# 3.半连接池
server.listen(5)
# 4.等待客户端连接
sock, address = server.accept()  # sock是双向通道 address是客户端地址
# 5.数据交互
sock.send(b'hello')  # 朝客户端发送数据
data = sock.recv(1024)  # 接收客户端发送的数据 1024bytes
print(data)
# b'get out'
sock.close()  # 断链接
server.close()  # 关机

客户端
import socket
# 1.产生一个socket对象
client = socket.socket()
# 2.连接服务端(拼接服务端的ip和port)
client.connect(('127.0.0.1', 8080))
# 3.数据交互
data = client.recv(1024)  # 接收服务端发送的数据
print(data)
# b'hello'
client.send(b'get out')  # 朝服务端发送数据
client.close()
# 4.关闭

代码优化

1.send与recv
客户端与服务端不能同时执行收、同时执行发,有一个发,另一个就是收

2.消息自定义
使用(input)获取用户数据即可

3.循环通信
给数据交互环节添加循环(while)即可

4.服务端能够持续提供服务,不会因为客户端断开连接而报错
异常捕获,一旦客户端断开连接,服务端结束通信循环,调到连接处等待

5.消息不能为空
判断是否为空,如果是则重新输入(主要针对客户端)

6.服务端频繁重启可能会报端口被占用的错(主要针对mac电脑)
from socket import SOL_SOCKET,SO_REUSEADDR
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)  #就是它,在bind前加

7.客户端异常退出会发送空消息(针对mac linux)
针对接收的消息加判断处理即可

服务端
import socket

while True:
    # 1.创建一个socket对象
    server = socket.socket()  # 括号内什么都不写 默认就是基于网络的TCP套接字
    # 2.绑定一个固定的地址(ip\port)
    server.bind(('127.0.0.1', 8080))  # 127.0.0.1本地回环地址(只允许自己的机器访问)
    # 3.半连接池
    try:
        server.listen(5)
        # 4.等待客户端连接
        sock, address = server.accept()  # sock是双向通道 address是客户端地址
        # 5.数据交互
        res = input('输入内容>>>:').strip()
        if len(res) == 0:
            res = '点错了,没消息'
        sock.send(res.encode('utf8'))  # 朝客户端发送数据
        data = sock.recv(1024)  # 接收客户端发送的数据 1024bytes
        print(data.decode('utf8'))
    except:
        continue
    
客户端
import socket

while True:
    # 1.产生一个socket对象
    client = socket.socket()
    # 2.连接服务端(拼接服务端的ip和port)
    client.connect(('127.0.0.1', 8080))
    # 3.数据交互
    data = client.recv(1024)  # 接收服务端发送的数据
    print(data.decode('utf8'))
    # b'hello'
    res = input('输入内容>>>:').strip()
    if len(res) == 0:
        res = '点错了,没消息'
    client.send(res.encode('utf8'))  # 朝客户端发送数据

半连接池

server.listen(5)
主要是为了做缓冲,避免太多无效等待

黏包问题

1.黏包问题
所谓粘包就是连续给对端发送两个或者两个以上的数据包,对端在一次收取中收到的数据包数量可能大于 1 个,当大于 1 个时,可能是几个包加上某个包的部分,或者干脆就是几个完整的包在一起。当然,也可能收到的数据只是一个包的部分,这种情况一般也叫半包

2.TCP特性
流式协议:即协议的内容是像流水一样的字节流,内容与内容之间没有明确的分界标志,需要我们人为地去给这些协议划分边界

3.struct模块
import struct

info = '我现在内心感到悲痛欲绝 而且这份悲痛正渐渐转变为杀意'
print(len(info))  # 数据原本的长度
# 26
res = struct.pack('i', len(info))  # 将数据原本的长度打包
print(len(res))  # 打包之后的长度是4
# 4
ret = struct.unpack('i', res)  # 将打包之后固定长度为4的数据拆包
print(ret[0])  # 又得到了原本数据的长度
# 26
'''
无论数据长度是多少,struct模块都可以打包成固定长度,然后基于固定长度,还可以反向解析出真实长度

1.将数据原本的长度打包成固定长度4
2.再根据报头解压出真实长度
3.根据真实长度接收即可
'''

原文地址:https://www.cnblogs.com/riuqi/p/16555669.html