Socket

Socket(套接字),是进程间通信的方式。网络间进程间通信。

Socket是应用层的概念

在Socket中,当建立连接的方式,通过传输层有两种建立连接协议的方式:TCP协议、UDP协议

 

基操

首先是导入socket模块



import socket



 

然后通过socket类初始化socket对象



socket.socket(AddressFamily,type)



 

其中:

  • AddressFamily:选择AF_INET即可
  • type:套接字类型,可以为:
  •   SOCK_STREAM:流式套接字。主要指TCP协议
  •   SOCK_DGRAM:数据报套接字。主要指UDP协议
import socket

# 创建一个流式套接字,用于TCP传输
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print('socket创建成功', s)
s.close()



 



import socket

# 创建一个数据报套接字,用于UDP传输
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

print('socket创建成功', s)
s.close()



 

TCP:传输速度慢,但稳定。(打电话)

UDP:传输速度快,但不稳定(写信)

TCP

下面以TCP的服务端和客户端写一遍

服务端

while循环(服务器一般不能随便重启,保持循环),把accept()接收连接、recv()接收信息、send()发送信息的代码放到循环中



# TCP服务端
import socket

# 创建一个流式套接字 用于TCP传输
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 绑定端口
server_socket.bind(('',10086))

# 监听 参数表示可以接收客户端的个数
server_socket.listen(5)

while 1:
    # 接收客户端的连接
    # 服务端会在这里阻塞等待,直到客户端连接上
    # 返回值1:连接的客户端的socket;返回值2:连接的客户端的信息 是一个元祖 包括地址和端口号
    client_socket,client_info = server_socket.accept()

    # 接收客户端发送过来的数据
    # recv()接收数据 注意与recvfrom()比较
    recv_data = client_socket.recv(1024)
    print(recv_data)
    print(recv_data.decode('gbk'))

    # 给客户端返回一条信息
    msg = 'get'
    client_socket.send(msg.encode('gbk'))

# 关闭socket
server_socket.close()



客户端

 



# TCP服务端
import socket

# 创建一个流式套接字 用于TCP传输
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

# 通过connect()函数连接服务端
# 参数是一个元组 里面包含服务端的地址和端口号
client_socket.connect(('192.168.30.35',10088))

# 给服务器发送一条消息
msg = '在吗'
client_socket.send(msg.encode('gbk'))

# 接收服务器返回等待消息
recv_data = client_socket.recv(1024)
print(recv_data)
print(recv_data.decode('gbk'))

# 关闭socket
client_socket.close()



 

UDP

  • UDP是没有建立连接,所以每次发送信息的时候,都指定目的地,使用的函数是 sendto 、相应的接受函数是 recvfrom
  • 比较TCP,是一开始就建立好连接,所以每次发送信息的时候,都无需再次指定目的地,使用的函数是 send 、相应接收函数是 recv

下面拿最UDP来写程序,我用网络调试助手设置其IP地址和端口号来检验代码:

UDP发送

python3 socket链接默认超时时间 socket.socket python_套接字



import socket

# 创建一个数据报套接字 用于UDP传输
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# sendto 通过udp发送信息
# 参数1 要发送的内容
# 参数2 发送的目的地 该参数是一个元组 里面有两个元素
#   1 目的地的IP地址
#   2 目的地的端口号
# s.sendto('hey!!'.encode(), ('192.168.30.35', 9527))
# 发送字符为中文,给encode()加入参数
msg = 'hey!!你好呀'
s.sendto(msg.encode(encoding='gbk'), ('192.168.30.35', 9527))

s.close()



python3 socket链接默认超时时间 socket.socket python_UDP_02

UDP接收

  • 在发送数据的时候,无需绑定端口号
  • 在接收数据的时候,才需要绑定端口号
  • Udp程序通过recvfrom接收信息
import socket

# 创建一个数据报套接字 用于UDP传输
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定地址和端口号
# 参数是一个元素 第一个元素是地址,第二个元素是端口号
# 不写则让系统自取便可
s.bind(('', 52077))

# recvfrom
# 返回值1 content 接收到的信息
# 返回值2 info 发送方的地址+端口号
while 1:
    content, info = s.recvfrom(1024)
    print(content)
    print(info)
    #content才是我们要的信息
    print(content.decode(encoding='gbk'))

s.close()



python3 socket链接默认超时时间 socket.socket python_套接字_03

输出结果:



b'hey hey \xba\xd9 \xba\xd9'
('192.168.30.35', 9527)
hey hey 嘿 嘿



 

发送和接收的原理:

在python中通过网络接收到的数据都是字节流,需要通过decode()解码后才能变成我们能够阅读的文字

python3 socket链接默认超时时间 socket.socket python_python_04

 

UDP广播

只有UDP才能发送广播,TCP不能发送

如果要发送广播消息,需要通过setsockopt允许当前套接字发送广播数据



import socket

# 创建一个数据报套接字 用于UDP传输
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 允许当前套接字发送广播
s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)

# 目标地址,发送到局域网各子机
dest = ('<broadcast>',9527)
msg = 'Hey!大家好,三姑六婆大家好'
s.sendto(msg.encode(encoding='gbk'),dest)

s.close()