36、基于TCP、UDP协议的嵌套字通信

一、套接字工作流程36、基于TCP、UDP协议的嵌套字通信

1.1、套接字流程

服务器端先初始化socket:(创建套接字模块)

和端口绑定bind:(将地址绑定到套接字)

对端口进行监听listen:(监听链接)

调用accept堵塞:(接收服务器链接)

等待客户端连接connect:(客户端尝试连接服务器)

客户端发送请求send:(客户端发出请求)

服务器接收请求并处理请求recv:(服务器接收请求)

将数据返回给客户端send:(服务器发出请求)

客户端读取数据recv:(客户端接收请求)

关闭连接close(关闭服务器)

一、基于TCP协议的嵌套字通信

TCP是基于链接的,所以需要先启动服务端,在启动客户端去连接服务端

1.1、名词定义

SOCK_STREAM:流式协议(tcp协议)

AF_INET:网络通讯协议

0.0.0.0:公网服务器地址

127.0.0.1:服务器地址(自己的,通常用来调试)

二、通讯循环

由于tcp是基于链接通信的,所以一旦程序执行完毕就会直接断开,所以需要在程序内添加while循环,保证可以持续服务

2.1、问题点  

由于tcp是基于链接通信的,连接的双方,所以:

1.一旦客户端单方向断开连接,服务器拿到的conn就是无效的,服务器在Windows上会直接报错,linux上会直接死循环

2.客户端发送的信息为空,应用程序会将信息发给操作系统,操作系统不会将空往外发送,因此,服务器就不会收到消息,而客户端则在等待消息

2.2、解决方案

1.使用异常捕获,捕获后中断程序

2.使用if判断,如果收到的消息为空,则跳出循环
三、连接循环

服务器的终极目标就是永不停机,所以需要将客户端连接服务器加入while

3.1、问题

端口占用:一个端口只能同时执行一个客户端,因此前一个未停止,下一个无法执行,在半连接池里的客户端可以输入内容排队等候

     accept限制了服务器连接客户端的数量,一旦超过将不会进入半连接池

3.2、解决方法

phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind((‘127.0.0.1‘,8080))

服务端

# 服务端应该满足的特点:
# 1、一直提供服务
# 2、并发地提供服务
import socket

# 1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议

# 2、绑定手机卡
phone.bind((‘127.0.0.1‘,8080)) # 0-65535, 1024以前的都被系统保留使用

# 3、开机
phone.listen(5) # 5指的是半连接池的大小
print(‘服务端启动完成,监听地址为:%s:%s‘ %(‘127.0.0.1‘,8080))

# 4、等待电话连接请求:拿到电话连接conn
# 加上链接循环
while True:
    conn,client_addr=phone.accept()

    # 5、通信:收\发消息
    while True:
        try:
            data=conn.recv(1024) # 最大接收的数据量为1024Bytes,收到的是bytes类型
            if len(data) == 0:
                # 在unix系统洗,一旦data收到的是空
                # 意味着是一种异常的行为:客户度非法断开了链接
                break
            print("客户端发来的消息:",data.decode(‘utf-8‘))
            conn.send(data.upper())
        except Exception:
            # 针对windows系统
            break

    # 6、关闭电话连接conn(必选的回收资源的操作)
    conn.close()

# 7、关机(可选操作)
phone.close()

客户端

import socket

#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议

#2、拨通服务端电话
phone.connect((‘127.0.0.1‘,8080))

#3、通信
while True:
    msg=input("输入要发送的消息>>>: ").strip() #msg=‘‘
    if len(msg) == 0:continue
    phone.send(msg.encode(‘utf-8‘))
    print(‘======?‘)
    data=phone.recv(1024)
    print(data.decode(‘utf-8‘))

#4、关闭连接(必选的回收资源的操作)
phone.close()

四、基于udp协议的套接字通信

udp是无链接的,所以无论哪一端都不会报错

服务器和客户端需要初始化socket,设定连接地址,接收数据,以及发出数据,最后断开连接

服务器

import socket

server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 数据报协议=》udp协议

server.bind((‘127.0.0.1‘,8081))    # IP地址

while True:
    data,client_addr=server.recvfrom(1024)   #接收信息
    server.sendto(data.upper(),client_addr)  #发出信息


server.close()

客户端

import socket

client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 流式协议=》tcp协议

while True:
    msg=input(‘>>>: ‘).strip()
    client.sendto(msg.encode(‘utf-8‘),(‘127.0.0.1‘,8081))   #发出信息,设置地址
    res=client.recvfrom(1024)  #接收信息
    print(res)

client.close()