文章目录

  • socket套接字
  • socket工作流程
    • Tcp 服务端:
    • Tcp 客户端:
  • 基于 Tcp 的scoket 服务端与客户端编程
    • 简易版
    • 加入链接循环
    • 加入通信循环
    • 支持并发的 Tcp 服务端
    • 常见问题
    • 半连接池
    • 黏包问题
    • 解决黏包问题

socket套接字

socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的
例如我们每天浏览网页、QQ 聊天、收发 email 等等

1.socket介绍
1.什么是socket?
socket套接字,是进程通信的一种实现方式
2.主要特点
主要针对不同主机之间的通信。即网络进程的通信,
几乎所有的网络都是通过socket来实现的
3.创建socket的基本流程
1. 创建socket流程,实现网络通信
2. 套接字使用流程 与 文件的使用流程很类似
1. 读写数据到文件的流程
- 打开或者创建文件,取得file对象
file=open()
- 通过file对象读写数据
file.read() file.write()
- 关闭file对象
file.close()
2. 创建socket流程,实现网络通信
1. 创建socket对象
2. 通过socket对象实现发送与接收数据
3. 关闭socket对象
2. socket.socket 创建一个 socket对象,该函数带有两个参数:
Address Family:地址族,可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
Type:套接字类型,可以是 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)或者 SOCK_STREAM(流式套接字,主要用于 TCP 协议)

socket工作流程

Tcp 服务端:

首先,需要拿到一个 socket 对象,socket 对象 与 ip+port 绑定,才能进行端口的监听;

然后,socket 对象 监听端口是否有请求,同时调用 accept方法,一直阻塞等待客户端的链接;

如果,有客户端的请求发来,那么服务端接受到请求之后,调用 read 方法,读取数据;

之后再处理请求,写回数据使用 write 方法(在 Python 中是 send 方法)

当需要断开链接时,服务端发送请求,客户端读取之后,在调用 close 方法发送断开的请求

服务端 read 收到断开请求,服务端再调用 close 结束链接

Tcp 客户端:

首先,需要拿到一个 socket 对象,调用 connect 方法,传入 IP 与端口,发送建立链接的请求;

之后,就可以进行数据交互,如果需要结束链接,直接调用 close 方法即可。

基于 Tcp 的scoket 服务端与客户端编程

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

简易版

服务端

import socket
import timeserver = socket.socket()# 注意传入的参数必须是一个元组或者列表
# ip'127.0.0.1',只能本机自己玩
# 如果写别的 IP 地址可以在局域网中一起玩
server.bind(('127.0.0.1', 8008))# 监听,半连接池 为 5,相当于队列中最多有 5 个,如果多余 5 个就会报错
# 同时只能服务一个人
server.listen(5)# 等待客户端的链接
# sock 是连接的对象, addr 是客户端地址
# 以后这个服务端和客户端,使用 sock 这个链接对象
sock, addr = server.accept()# 接受客户端发了的数据
# 传入的参数为一次接受的字节
data = sock.recv(1024)print(f'接收到来自{addr}的数据{data.decode("utf-8")}')# 服务端给客户端发送消息
data_send = f'收到了你发送的 {data}'.encode('utf-8')
# 注意:必须传送二进制的格式
sock.send(data_send)time.sleep(3)
# 关闭连接对象,此时服务端并没有关闭!!!
sock.close()# 关闭服务端
server.close()

客户端

import socketclient = socket.socket()# 连接服务端的地址加端口
client.connect(('127.0.0.1', 8008))# 连上以后就可以发送消息了
client.send(b'sb')# 收到服务端返回的消息
data = client.recv(1024)
print(data.decode('utf-8'))client.close()

加入链接循环

只加入链接循环,此时服务端会一直接收,相当于死循环,服务端不会自动断开

服务端

import socketserver = socket.socket()server.bind(('127.0.0.1', 8008))server.listen(5)
print('等待客户端的链接')# 等待客户端的链接
# 链接循环
while True:sock, addr = server.accept()# 接受客户端发了的数据data = sock.recv(1024)print(f'接收到来自{addr}的数据--{data.decode("utf-8")}')# 服务端给客户端发送消息data_send = f'收到了你发送的 {data}'.encode('utf-8')# 注意:必须传送二进制的格式sock.send(data_send)# 关闭连接对象,此时服务端并没有关闭!!!sock.close()# 关闭服务端
server.close()

客户端

import socketclient = socket.socket()# 连接服务端的地址加端口
client.connect(('127.0.0.1', 8008))# 连上以后就可以发送消息了
client.send(b'sb')# 收到服务端返回的消息
data = client.recv(1024)
print(data.decode('utf-8'))client.close()

加入通信循环

加入通信循环,此时客户端可以多次发送数据

服务端

import socketserver = socket.socket()
server.bind(('127.0.0.1', 8008))
server.listen(5)
print('等待客户端的链接')while True:sock, addr = server.accept()print(f'客户端{addr}已连接')# 等待接受客户端发的数据# 如果客户端没法,就会一直等待下去while True:try:# 同一个客户端,不停地发送data = sock.recv(1024)# 当客户端主动断开后,客户端会发送一个空的数据过来# 此时服务端必须对这种情况进行处理,否则会出现死循环if len(data) == 0:print(f'客户端{addr}已断开', '\n')breakprint(f'接收到来自{addr}的数据--{data.decode("utf-8")}')data_send = f'收到了你发送的 {data}'.encode('utf-8')sock.send(data_send)except Exception as e:print(e)breaksock.close()# 关闭服务端
server.close()

客户端

import socketclient = socket.socket()
client.connect(('127.0.0.1', 8008))
# 连上以后就可以发送消息了while True:data = input('输入发送给服务端的消息(q to quit):')if data == 'q': breakclient.send(data.encode("utf-8"))data = client.recv(1024)print(data.decode('utf-8'))client.close()

支持并发的 Tcp 服务端

在这里是开启多进程完成的并发,可以换成多线程,只需要将 Process 类换成 Thread 类。

import socket
from multiprocessing import Processdef talk(sock,addr):print('客户端连接成功', addr)while True:try:data = sock.recv(1024)if len(data) == 0:print(f'客户端{addr}已断开', '\n')breakprint(f'接收到来自{addr}的数据--{data.decode("utf-8")}')data_send = f'收到了你发送的 {data}'.encode('utf-8')sock.send(data_send)except Exception as e:print(e)breaksock.close()if __name__ == '__main__':server = socket.socket()server.bind(('127.0.0.1', 81))server.listen(5)while True:sock,addr = server.accept()print(f'客户端{addr}已连接')# 连接上一个客户端之后开启一个进程,对该客户端进行服务p = Process(target=talk, args=(sock, addr))p.start()server.close()

常见问题

1.发送消息不能为空
统计长度并判断即可
2.反复重启服务端可能会报错>>>:address in use
这个错在苹果电脑报的频繁 windows频率较少
from socket import SOL_SOCKET,SO_REUSEADDR
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 在bind前加
3.链接循环
“”"
如果是windows 客户端异常退出之后服务端会直接报错
处理方式
异常处理
如果是mac或linux 服务端会接收到一个空消息
处理方式
len判断
“”"
客户端如果异常断开 服务端代码应该重新回到accept等待新的客人
目前我们的服务端只能实现一次服务一个人 不能做到同事服务多个 学了并发才可以实现

半连接池

listen(5)
# py文件默认同一时间只能运行一次 如果想单独分开运行多次# 半连接池设置的最大等待人数  >>>:  节省资源 提高效率

黏包问题

data1 = conn.recv(1024)
print(data1)
data2 = conn.recv(1024)
print(data2)
data3 = conn.recv(1024)
print(data3)client.send(b'hello')
client.send(b'jason')
client.send(b'kevin')
"""
三次打印的结果b'hellojasonkevin'b''b''
"""

TCP协议的特点

会将数据量比较小并且时间间隔比较短的数据整合到一起发送
并且还会受制于recv括号内的数字大小(核心问题!!!)
流式协议:跟水流一样不间断
“”"
问题产生的原因其实是因为recv括号内我们不知道即将要接收的数据到底多大
如果每次接收的数据我们都能够精确的知道它的大小 那么肯定不会出现黏包
“”"
思路:
困扰我们的核心问题是不知道即将要接收的数据多大
如果能够精准的知道数据量多大 那么黏包问题就自动解决了!!!

解决黏包问题

方向:精准获取数据的大小

# struct模块import structdata1 = 'hello world!'print(len(data1))  # 12res1 = struct.pack('i', len(data1))  # 第一个参数是格式 写i就可以了print(len(res1))  # 4ret1 = struct.unpack('i', res1)print(ret1)  # (12,)data2 = 'hello baby baby baby baby baby baby baby baby'print(len(data2))  # 45res2 = struct.pack('i', len(data2))print(len(res2))  # 4ret2 = struct.unpack('i', res2)print(ret2)  # (45,)

pack可以将任意长度的数字打包成固定长度
unpack可以将固定长度的数字解包成打包之前数据真实的长度
思路:
1.先将真实数据打包成固定长度的包
2.将固定长度的包先发给对方
3.对方接收到包之后再解包获取真实数据长度
4.接收真实数据长度

【socket套接字】相关推荐

  1. day7 面向对象进阶、socket套接字

    文章目录 1. 静态方法.类方法 1.1 静态方法 1.2 类方法 2. 属性方法 3. 类的一些成员方法 4. 反射 5. 异常处理 6. socket 套接字 1. 静态方法.类方法 1.1 静态 ...

  2. 三、初识Socket套接字结构体

    一.初识Socket套接字结构体 1.通用套接字结构体类型 struct sockaddr{sa_family_t sa_family; //协议簇char sa_data[14]; //协议簇数据} ...

  3. 基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

    基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socketserver = socket.socket(socket.AF_INET,socket.S ...

  4. Python 技术篇-socket套接字实现两个窗口间消息传递实例演示,TCP实现

    上一篇:Python 技术篇-socket 套接字实现服务器客户端消息传递,UDP 实现 本篇介绍用 TCP 来实现. socket 实现客户端服务器的消息传递有 TCP 和 UDP 两种方式. TC ...

  5. Python 技术篇-socket套接字实现服务器客户端消息传递实例演示,UDP实现

    上一篇:Python 技术篇-socket 套接字实现两个窗口间消息传递,TCP 实现 本篇介绍用 UDP 来实现. socket 套接字实现服务器客户端消息传递有 UDP 和 TCP 两种形式.他们 ...

  6. java实现套接字网络编程_Java网络编程(一)Socket套接字

    一.基础知识 1.TCP:传输控制协议. 2.UDP:用户数据报协议. 二.IP地址封装 1.InetAddress类的常用方法 getLocalHost() 返回本地主机的InetAddress对象 ...

  7. C语言socket bind()函数(为socket套接字关联了一个相应的地址与端口号)

    #include <sys/socket.h>int bind(int socket, const struct sockaddr *address, socklen_t address_ ...

  8. Python开发基础----异常处理、socket套接字基础1

    异常处理 错误 程序里的错误一般分为两种: 1.语法错误,这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正 2.逻辑错误,人为造成的错误,如数据类型错误.调用方法错误等,这些解 ...

  9. socket 套接字的基本概念

    什么是套接字: socket套接字:一套网络通信的接口 (API), 一套函数, 本质是伪文件. 在网络环境中唯一的标识一个进程需要 IP 和端口,这个进程就是 socket,因此 socket 需要 ...

  10. 网络编程(part11)--socket模块方法及socket套接字属性

    鄙人学习笔记 文章目录 socket模块方法及socket套接字属性 部分socket模块方法 举个例子 套接字属性 举个例子 写个案例 socket模块方法及socket套接字属性 部分socket ...

最新文章

  1. Pulsar:下一代消息引擎真的这么强吗?
  2. 腾讯医疗AI新突破:提出器官神经网络,全自动辅助头颈放疗规划 | 论文
  3. 由浅入深剖析go channel
  4. 10、mybatis中缓存的使用
  5. asp.net ViewState详解
  6. 怎样才能减少汽车油耗呢?
  7. Kotlin 能追赶上 Java 的步伐吗?
  8. Mac电脑「空格键」的妙用,原来有这么多功能
  9. Jetbrains:设置ctrl+鼠标滚动控制代码字体大小
  10. 【QT】QT网络编程简介
  11. java中Excel转图片实现
  12. Web客户端语言HTML、XHTML和XML相关知识介绍
  13. elasticsearch实现类似京东的商品搜索效果(elasticsearch动态聚合)
  14. arcgis api 4.13 —— Layer详细介绍
  15. 火星玩家Mars全球合伙人招募计划启动:为电核户外可持续发展贡献实质力量
  16. 怎么用EDIUS将静帧图片做出动态特效
  17. 华为私有云的搭建方案_如何搭建私有云
  18. 关于宗海图WGS84转CGCS2000的问题
  19. RHCS+Conga+GFS+cLVM共享存储的高可用性web集群
  20. 人机融合智能中的计算-算计问题

热门文章

  1. 对favicon进行base64 编码?
  2. CAD/CASS高程点自动避让插件、高程点不压线插件(可自动处理高程点注记压线压地物,也可自动处理高程点注记互相压盖)
  3. 如何利用火狐控制台下载网页图片
  4. lsblk命令及uuid查看
  5. 2015华为软件精英挑战赛 客户端源码 德州扑克
  6. 轻量级图卷积网络LightGCN讲解与实践
  7. 旋转or跳跃?基于互联网视频的人体运动捕捉
  8. 零成本系列丨盏茶的功夫,零成本搭建了一个自己的博客网站
  9. Unity 二段跳的正确方法和一些易错点
  10. 训练神经网络的秘诀,Andrej Karpathy大神的刷屏之作