Python网络编程
- 注意事项
- Socket编程思路
- 服务端
- 客户端
- TCP编程
- 服务器端
- 客户端
- 多线程创建服务器
- UDP编程
注意事项
- 在python3之后,socket传递的都是byte数据,字符串需要转换string.encode()。另一端接受Byte数据想要转为字符串,需要bytes.decode()。
- accept()和recv()方法都是阻塞。阻塞是指,程序会停在那里,一直等到有数据过来。
Socket编程思路
服务端
- 创建套接字,绑定套接字到本地IP与端口:
socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建套接字
bind() #绑定ip
注:
socket.AF_INET : ipv4
socket.AF_INET6 : ipv6
SOCK_STREAM :TCP
SOCK_DGRAM : UDP
- 开始监听 : s.listen()
- 进入循坏,不断接受客户端的连接请求:s.aceept()
- 接受传来的数据,或发送数据给对方 : s.recv() s.sendall()
- 传输完毕,关闭套接字 : s.close()
客户端
- 创建套接字,连接服务器地址:
socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.connect()
- 连接后发送数据和接收数据:s.sendall(), s.recv()
- 传输完毕后,关闭套接字:s.close()
Python的Socket编程,通常分为TCP和UDP编程两种
前者是带连接的可靠传输服务,每次通信要握手,结束传输也要挥手,数据会被检验。
后者是不带连接的传输服务,简单粗暴不加控制和检查的一股脑将数据发送出去的方式,通常安全等级要求不高的业务场景,比如文件下载。
TCP编程
服务器端
#sever.py
import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket() #创建套接字
sk.bind(ip_port) #绑定服务地址
sk.listen(5) #监听连接请求
print('启动socket服务,等待客户端连接...')
conn,address = sk.accept() #等待连接,此处自动阻塞
#死循环,等待客户端发送exit,才关闭连接
while True:
client_data = conn.recv(1024).decode()
if client_data == 'exit':
exit("通信结束")
conn.sendall('服务器已经收到你的信息'.encode()) #回馈信息给客户端
conn.close()
客户端
import socket
ip_port = ('127.0.0.1',9999)
s = socket.socket()
#连接服务器
s.connect(ip_port)
while True:
inp = input("请输入要发送的内容:").strip()
if not inp:
continue
s.sendall(inp.encode())
if inp == "exit":#断开连接
print("结束通讯")
break
server_reply = s.recv(1024).decode()
print(server_reply)
s.close() #关闭连
多线程创建服务器
import socket
import threading
def link_handler(link,client):
"""
该函数为线程需要执行的函数,负责具体的服务器和客户端之间的通信工作
:param link: 当前线程处理的连接
:param client: 客户端ip和端口信息,一个二元组
:return: None
"""
print("服务器开始接受来自[%s:%s]的请求..." % (client[0],client[1]))
while True:
client_data = link.recv(1024).decode()
if client_data == "exit":
print("结束与[%s:%s]的通信..." % (client[0],client[1]))
break
print("来自[%s:%s]的客户端向你发来信息:%s" % (client[0], client[1], client_data))
link.sendall('服务器已经收到你的信息'.encode())
link.close()
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
print('启动socket服务,等待客户端连接...')
while True:
conn,address = sk.accept()
#没打过有新的连接,自动创建一个新的线程
#并将连接对象和访问者的ip信息作为参数传递给线程的执行函数
t = threading.Thread(target=link_handler,args=(conn,address))
t.start()
多开几个客户端运行,可以看出,服务器能与多个客户端通信
UDP编程
由于UDP没有握手和挥手的过程,因此accept()和connect()方法都不需要。
# @Description : UDP服务端
import socket
ip_port = ('127.0.0.1',9998)
sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) #创建套接字
sk.bind(ip_port) #绑定服务地址
#死循环,等待客户端发送exit,才关闭连接
while True:
client_data = sk.recv(1024).decode()
print(client_data)
if client_data == 'exit':
exit("通信结束")
break
sk.close()
# @Description : UDP客户端
import socket
ip_port = ('127.0.0.1', 9998)
sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
while True:
inp = input('发送的消息:').strip()
sk.sendto(inp.encode(), ip_port)
if inp == 'exit':
break
sk.close()