Scoket层

【一】Scoket层在哪

Scoket层

【二】套接字工作流程

一个生活中的场景。

你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。
等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

Scoket层

【0】服务端流程

先从服务器端说起。

服务器端先初始化Socket
然后与端口绑定(bind),对端口进行监听(listen)
调用accept阻塞,等待客户端连接。
在这时如果有个客户端初始化一个Socket
然后连接服务器(connect)

如果连接成功,这时客户端与服务器端的连接就建立了。

客户端发送数据请求,服务器端接收请求并处理请求
然后把回应数据发送给客户端,客户端读取数据
最后关闭连接,一次交互结束

socket()模块函数用法

import socket
  socket.socket(socket_family,socket_type,protocal=0)
  socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。
  
 # 获取tcp/ip套接字
  tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
 # 获取udp/ip套接字
  udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

 # 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
 #  例如tcpSock = socket(AF_INET, SOCK_STREAM

【1】服务端套接字函数

s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

【2】客户端套接字函数

s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

【3】公共用途的套接字函数

s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

【4】面向锁的套接字方法

s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间

【5】面向文件的套接字的函数

s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

【三】基于TCP的套接字

【1】方法简介

tcp是基于链接的

必须先启动服务端
然后再启动客户端去链接服务端

tcp服务端

server = socket() #创建服务器套接字
server.bind()      #把地址绑定到套接字
server.listen()      #监听链接
inf_loop:      #服务器无限循环
    conn = server.accept() #接受客户端链接
    comm_loop:         #通讯循环
        conn.recv()/conn.send() #对话(接收与发送)
    conn.close()    #关闭客户端套接字
server.close()        #关闭服务器套接字(可选)

tcp 客户端

client = socket()    # 创建客户套接字
client.connect()    # 尝试连接服务器
comm_loop:        # 通讯循环
    client.send()/client.recv()    # 对话(发送/接收)
client.close()            # 关闭客户套接字

【2】打电话模型

socket通信流程与打电话流程类似

我们就以打电话为例来实现一个low版的套接字通信

(1)服务端

import socket

ip_port = ('127.0.0.1', 9000)  # 电话卡
BUFSIZE = 1024  # 收发消息的尺寸
servser = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 买手机
servser.bind(ip_port)  # 手机插卡
servser.listen(5)  # 手机待机

conn, addr = servser.accept()  # 手机接电话
# print(conn)
# print(addr)
print('接到来自%s的电话' % addr[0])

msg = conn.recv(BUFSIZE)  # 听消息,听话
print(msg, type(msg))

conn.send(msg.upper())  # 发消息,说话

conn.close()  # 挂电话

servser.close()  # 手机关机

(2)客户端

import socket

ip_port = ('127.0.0.1', 9000)
BUFSIZE = 1024
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect_ex(ip_port)  # 拨电话

client.send('dream is handsome'.encode('utf-8'))  # 发消息,说话(只能发送字节类型)

feedback = client.recv(BUFSIZE)  # 收消息,听话
print(feedback.decode('utf-8'))

client.close()  # 挂电话

【3】打电话模型升级

加上链接循环与通信循环

import socket

# 电话卡
ip_port = ('127.0.0.1', 8081)
BUFSIZE = 1024

# 买手机
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 手机插卡
server.bind(ip_port)

# 手机待机
server.listen(5)

# 新增接收链接循环,可以不停的接电话
while True:
    # 手机接电话
    conn, addr = s.accept()
    # print(conn)
    # print(addr)
    print('接到来自%s的电话' % addr[0])

    # 新增通信循环,可以不断的通信,收发消息
    while True:
        # 听消息,听话
        msg = conn.recv(BUFSIZE)

        # 如果不加,那么正在链接的客户端突然断开,recv便不再阻塞,死循环发生
        # if len(msg) == 0:break        

        print(msg, type(msg))

        # 发消息,说话
        conn.send(msg.upper())

    # 挂电话
    conn.close()

# 手机关机
server.close()

客户端改进版

import socket

ip_port = ('127.0.0.1', 8081)
BUFSIZE = 1024
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 拨电话
client.connect_ex(ip_port)  

# 新增通信循环,客户端可以不断发收消息
while True:  
    msg = input('>>: ').strip()
    if len(msg) == 0: continue
    # 发消息,说话(只能发送字节类型)
    client.send(msg.encode('utf-8'))
    
    # 收消息,听话
    feedback = client.recv(BUFSIZE)  
    print(feedback.decode('utf-8'))

# 挂电话
client.close()
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...