编程语言
首页 > 编程语言> > 网络编程(二)

网络编程(二)

作者:互联网

网络编程(二)

socket套接字简介

# socket套接字是一门技术
	socket套接字可以帮我们实现C/S架构的程序两端交互
    socket套接字可以通过python内置的socket模块快速实现OSI七层操作
    """
    以后我们写软件连socket的影子都看不到 因为被封装起来
    socket是最底层的原理 很多框架都封装了 其实我们不需要深入研究
    """

socket模块

# 编程思想
	对于C/S架构的程序,无论编写还是运行,都要遵循:
        '优先考虑服务端,有了服务才能有客户'
# 服务端代码
	import socket

    server = socket.socket()  # 获取连接对象
    server.bind(('127.0.0.1',8080))  # 给连接对象绑定地址
    server.listen(5)  # 允许最大排队数  这个数加上正在连接数就是最大连接数
    sock, addr = server.accept()  # 阻塞程序,没有获取到连接的客户端会阻塞程序运行
    print(addr)
    while True:  # 循环通信
        data = sock.recv(1024)  # 从连接里获取客户端的数据
        print(data.decode('utf8'))
        msg = input('>').strip()
        sock.send(msg.encode('utf8'))  # 通过连接把数据发给客户端
    sock.close()  # 关闭与客户端连接
    server.close()  # 关闭连接对象
    
# 客户端代码
	import socket

    client = socket.socket()  # 获取连接对象
    client.connect(('127.0.0.1',8080))  # 绑定连接服务端的地址
    while True:  # 循环通信
        msg = input('>').strip()
        client.send(msg.encode('utf8'))  # 发数据到服务端
        data = client.recv(1024)  # 获取服务端发来的数据
        print(data.decode('utf8'))
    client.close() # 关闭连接
    
###########################
服务端与客户端首次交互
	一边是recv那么另一边必须是send  两边不能相同 否则就'冷战'了
###########################

通信循环

# 思路
	1.所有通信消息要用户事实输入
    	利用input获取用户输入信息
    2.接收一次消息之后不能结束程序,应当获取输入,返回消息,然后等待下一次接发消息
    	利用While循环实现
# 代码编写
	详见上段代码

代码优化及链接循环

1.不能发空消息
	搞个if判断len(用户输入即可)
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 ='aaa'
data2 ='aaa'
data3 ='aaa'
client.send(data1.encode('utf8'))
client.send(data2.encode('utf8'))
client.send(data3.encode('utf8'))

# 服务端
data1 = sock.recv(1024)
print(data1)
data2 = sock.recv(1024)
print(data2)
data3 = sock.recv(1024)
print(data3)

# 客户端输出
b'aaaaaaaaa'
b''
b''

为什么发了三次数据,结果全都在第一次数据里?
"""
# TCP协议的特点
	会将数据量比较小并且时间间隔比较短的数据整合到一起发送
  并且还会受制于recv括号内的数字大小(核心问题!!!)
  流式协议:跟水流一样不间断
    
"""
"""
问题产生的原因其实是因为recv括号内我们不知道即将要接收的数据到底多大
如果每次接收的数据我们都能够精确的知道它的大小 那么肯定不会出现黏包
"""
eg:
    data1 = sock.recv(3)
    print(data1)
    data2 = sock.recv(3)
    print(data2)
    data3 = sock.recv(3)
    print(data3)
    # 客户端输出
    b'aaa'
    b'aaa'
    b'aaa'

解决黏包问题

解决思路:
    我们可以发送固定大小的数据,客户端接收就不会出现黏包
    
# struct模块
	import struct

    data1 = 'Hello world!'
    data2 = 'afdkjhfdafklajflkhaslfjahfjkahflksafjl'
    print(len(data1), len(data2))  # 12 38
    ret1 = struct.pack('i', len(data1))
    ret2 = struct.pack('i', len(data2))
    print(len(ret1), len(ret2))  # 4 4
    res1 = struct.unpack('i',ret1)
    res2 = struct.unpack('i',ret2)
    print(res1, res2)  # (12,) (38,)
    
# 具体解决黏包思路
	1.先将用struct模块打包成固定长度
    2.把打包后的长度发过去
    3.对方用unpack解析获取真实长度
    4.根据真实长度用recv(真实长度)接收数据

代码演示

1.编写一个cs架构的软件
	就两个功能
  	一个视频下载:从服务端下载视频
    一个视频上传:从客户端上传视频
 	"""
 	只要实现就可以 无需整合(如果能做到更好)
 	"""
# 代码
	服务端
    import socket

    # 获取连接对象
    import struct

    server_packer = socket.socket()
    server_packer.bind(('127.0.0.1',8081))
    server_packer.listen(1)
    sock,addr = server_packer.accept()
    # 读取视频文件
    with open('1.mp4','rb') as f:
        data = f.read()
    # 打包
    ret = struct.pack('i', len(data))
    # 发送打包后的数据
    sock.send(ret)
    # 发送真实数据
    sock.send(data)
    sock.close()
    server_packer.close()
    
    客户端
    import struct
    import socket

    # 获取连接对象
    client = socket.socket()
    client.connect(('127.0.0.1',8081))
    # 获取打包后长度并解析
    ret = client.recv(4)
    res = struct.unpack('i',ret)
    # 根据解析的长度获取真实数据
    data = client.recv(res[0])
    # 写入文件
    with open('2.mp4','wb') as f:
        f.write(data)
    client.close()
    

标签:socket,编程,sock,网络,client,recv,服务端,客户端
来源: https://www.cnblogs.com/cxysbyh/p/16150577.html