C/C++教程

socket套接字

本文主要是介绍socket套接字,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • socket套接字简介
  • socket模块
  • 通信循环
  • 代码优化及链接循环
  • 半连接池
  • 黏包问题
  • 黏包问题的解决

socket套接字简介

# 需求:编写cs架构的程序 实现数据交互
	需要编写OSO七层相当复杂,但是由于OSI七层是所有cs架构程序都需要经历的过程,所以由固定的模块
    socket模块:提供了快捷方式不需要自己处理每一层
'''
我们写软件,是看不到socket的,因为都被封装了起来
socket是最低层的原理,很多框架都被封装,不需要深入研究
'''

socket模块

cs架构的软件无论实在编写还是运行,都应该先考虑服务端
# 服务端
import socket

server = socket.socket()
"""
通过查看源码得知 
括号内不写参数默认就是基于网络的遵循TCP协议的套接字
"""

server.bind(('127.0.0.1', 8008))
"""
服务端应该具备的特征
    固定的地址
127.0.0.1是计算机的本地回环地址 只有当前计算机本身可以访问
"""
server.listen(3)
'''半连接池:可以决定客户端的等待人数'''
sock, addr = server.accept()
"""
listen和accept对应TCP三次握手服务端的两个状态
"""
print(addr)
msg = sock.recv(1024)
print(msg.decode('utf8'))
sock.send('hello client'.encode('utf8'))
sock.close()
server.close()

#  客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1',8008))
client.send('hello world'.encode('utf8'))
msg = client.recv(1024)
print(msg.decode('utf8'))
client.close()
'''
服务端与客户端的recv与send必须错开,不能同时存在,否则两边,都等待消息或者发送消息,程序阻塞
'''

通信循环

1.解决消息固定的问题
	利用input获取用户输入
2.解决通信循环问题
# 服务端
import socket

server = socket.socket()
server.bind(('127.0.0.1', 8008))
server.listen(3)
clint, addr = server.accept()
while True:
    msg = clint.recv(1024)
    print(msg.decode('utf8'))
    msg_send = input('请输入信息:')
    clint.send(msg_send.encode('utf8'))
clint.close()
server.close()

# 客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1',8008))
while True:
    msg_send = input('请输入信息:')
    client.send(msg_send.encode('utf8'))
    msg = client.recv(1024)
    print(msg.decode('utf8'))
client.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判断
'''
# 服务端
import socket
from socket import SOL_SOCKET,SO_REUSEADDR



server = socket.socket()
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1', 8008))
server.listen(3)
clint, addr = server.accept()
while True:
    try:
        msg = clint.recv(1024)
        print(msg.decode('utf8'))
        msg_send = input('请输入信息:')
        if len(msg_send) == 0:
            continue
        clint.send(msg_send.encode('utf8'))
    except Exception as f:
        print('客户端断开链接')
        break
clint.close()
server.close()

# 客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1',8008))
while True:
    msg_send = input('请输入信息:')
    if len(msg_send) == 0:
        continue
    client.send(msg_send.encode('utf8'))
    msg = client.recv(1024)
    print(msg.decode('utf8'))
client.close()


客户端如果异常断开 服务端代码应该重新回到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 struct
msg = 'hello world'
print(len(msg))  # 11
res = struct.pack('i',len(msg)) #第一个参数是格式
print(len(res))  # 4
res1 = struct.unpack('i',res)
print(len(res1))  # (11,) 

data2 = 'hello baby baby baby baby baby baby baby baby'
  print(len(data2))  # 45
  res2 = struct.pack('i', len(data2))
  print(len(res2))  # 4
  ret2 = struct.unpack('i', res2)
  print(ret2)  # (45,)
    
'''
pack可以将任意长度的数据打包成固定长度
unpack可以将固定长度的数据解包成打包之前的长度

解决黏包问题思路:
	1.将真是数据打包成固定长度的包
	2.将福哦顶长度的包先发给对方
	3.对方接收到包之后进行解包获取真实数据长度
	4.接收真实数据长度
'''
这篇关于socket套接字的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!