第八篇:网络协议

本文介绍了Python中Socket套接字的基础知识,包括TCP和UDP套接字的使用。在TCP套接字中,详细阐述了如何通过Socket实现客户端和服务端的连接,并解释了TCP的粘包现象及其解决方案。而在UDP套接字中,展示了其无连接特性和并发效果。此外,还利用SocketServer实现了基于TCP的并发服务端,展示了如何处理多个客户端的并发请求。
摘要由CSDN通过智能技术生成
1、Socket套接字(无法实现并发)
客服端和服务端架构:c/s架构
osi七层:
物理层、数据链路层(MAC地址)、网络层(IP)、传输层(TCP/UDP)、会话层、表示层和应用层
Socket套接字是应用层和TCP/UDP协议通信的中间的抽象层,它是一组接口,把复杂的TCP/UDP协议隐藏在
Socket接口后面,让Socket去组织数据,以符合指定协议。
Socket套接字有两种:基于文件型(AF-UNX)和基于网络型(AF-INET,重要)
基于TCP的套接字:TCP是基于链接的,必须先启动服务端,然后再启动客户端。
服务端:
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind((ip+端口))
phone.listen(5)
conn,addr = phone.accept()			addr[0]:ip
data = conn.recv()
conn.sendall()
conn.close()
phone.close()
客户端:
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect_ex((ip+端口))
phone.sendall(数据)
phone.recv(1024)
phone.close()
基于UDP的套接字:UDP是无链接的(可以实现并发效果),先启动那一端都不会报错。
服务端:
import socket
ip_port = ('192.168.1.5',8080)
bufsize = 1024
u_phone = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
u_phone.bind(ip_port)

while True:
    msg,addr = u_phone.recvfrom(bufsize)
    print(msg,addr)
    u_phone.sendto(msg.upper(),addr)
客户端:
import socket
ip_port = ('192.168.1.5',8080)
bufsize = 1024
u_phone = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    msg = input('>>:').strip()
    if not msg:break
    u_phone.sendto(msg.encode('utf8'),ip_port)
    data,addr = u_phone.recvfrom(bufsize)
    print(data.decode('utf8'),addr)
2、粘包
粘包现象:执行两个命令,两个命令的结果粘到一块。
两种粘包现象:发送端要等缓冲区满才发送,造成粘包;接收端不及时接收缓冲区的包,造成粘包。
只有TCP有粘包现象(2种:数据量小,一次发送;数据量多,多次接收),
UDP没有粘包现象(一次发送对应一次接收),但会出现数据丢失,
因此TCP(传输控制协议)是可靠传输,UDP(用户数据报协议)是不可靠传输。
解决:根源在于接收端不知道发送端要传的字节流长度,所以解决粘包的方法是让发送端在发送前,
让接收端知道要发的字节流大小,然后接收端循环接收。
服务端更改内容:
from functools import partial
import struct
data = '数据内容'
length = len(data)
data_length = struct.pack('i',length)
conn.send(data_length)
conn.send(data)
客户端更改内容:
length_data = tcp_client.recv(4)
length = struct.unpack('i',length_data)[0]
recv_size = 0
recv_msg = ''
while recv_size < length:
    recv_msg += tcp_client.recv(1024).decode('utf8')
    recv_size = len(recv_msg)
	
partial(tcp_client.recv,1024)
partial:偏函数,默认把1024传递给tcp_client.recv函数的第一个参数
struct模块:该模块可以把一个类型,如数字转变成固定长度的bytes
struct.pack('i',12345) 				转换成固定长度的字节
struct.unpack('i',length)[0]		把固定长度的字节转换成数字

客户端:
from functools import partial
import struct
from socket import *
tcp_service = socket(AF_INET,SOCK_STREAM)
tcp_service.bind(('192.168.1.5',8080))
tcp_service.listen(5)
conn,addr = tcp_service.accept()
print(conn,addr)
data = input('>>:').strip()
length = len(data)
data_length = struct.pack('i',length)
conn.send(data_length)
conn.send(data.encode('utf8'))
服务端:
import struct
from functools import partial
from socket import *
tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect_ex(('192.168.1.5',8080))
l1 = input('>>:').strip()
tcp_client.sendall(l1.encode('utf8'))
length_data = tcp_client.recv(4)
length = struct.unpack('i',length_data)[0]
recv_size = 0
recv_msg = ''
while recv_size < length:
    recv_msg += tcp_client.recv(1024).decode('utf8')
    recv_size = len(recv_msg)
print(recv_msg)
3、socketserver实现并发
基于tcp的socketserver我们自定义的类中:
self.server即套接字对象;
self.request即一个链接
self.client_address即客户端地址
基于udp的socketserver我们自定义的类中:
self.request是一个元组(第一个元素是客户端发来的数据,第二个是服务端的udp套接字对象)
self.client_address即客户端地址
基于tcp的服务端:
import socketserver
class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.server)
        print(self.request)
        print(self.client_address)

        while True:
            data = self.request.recv(1024)
            print('收到的消息是%s'%(data.decode('utf8')))

            self.request.sendall(data.upper())


s = socketserver.ThreadingTCPServer(('192.168.1.5',8080),Myserver)
s.serve_forever()
基于udp的服务端
import socketserver
class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request)
        print(self.request[0])
        print(self.request[1])
        self.request[1].sendto(self.request[0].upper(),self.client_address)

s = socketserver.ThreadingUDPServer(('192.168.1.5',8080),Myserver)
s.serve_forever()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值