TCP编程
TCP/IP介绍:https://www.cnblogs.com/onepixel/p/7092302.html
客户端
大多数连接都是可靠的TCP连接。创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器。我们要创建一个基于TCP连接的Socket,可以这样做:
import socket
import threading
import time
def tcp_link(sock, addr):
"""
每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接
连接建立后,服务器首先发一条欢迎消息,然后等待客户端数据,并加上Hello再发送给客户端。
如果客户端发送了exit字符串,就直接关闭连接。
"""
print('Accept new connection from %s:%s...' % addr)
sock.send(b'Welcome!')
while True:
data = sock.recv(1024) # 一次接收1024个字节的信息
time.sleep(1)
if not data or data.decode('utf-8') == 'exit':
break
sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
sock.close()
print('Connection from %s:%s closed.' % addr)
if __name__ == '__main__':
# 创建一个基于IPv4和TCP协议的Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定监听的地址和端口
s.bind(('127.0.0.1', 9999))
# 调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量
s.listen(5)
print('Waiting for connection...')
# 服务器程序通过一个永久循环来接受来自客户端的连接,accept()会等待并返回一个客户端的连接
while True:
# 接受一个新连接:
sock, addr = s.accept()
# 创建新线程来处理TCP连接:
t = threading.Thread(target=tcp_link, args=(sock, addr))
# 开启线程
t.start()
然后我们开启服务器:
image.png
编写一个客户端程序:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
s.connect(('127.0.0.1', 9999))
# 接收欢迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
# 发送数据:
s.send(data)
print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()
运行客户端程序:
image.png
同时服务端响应:
image.png
UDP编程
TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据。相对TCP,UDP则是面向无连接的协议。
使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。
虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。
编写服务端:
import socket
# 创建一个基于IPv4和UDP协议的Socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定监听的地址和端口
s.bind(('127.0.0.1', 9999))
# 不需要调用listen()方法,而是直接接收来自任何客户端的数据
print('Bind UDP on 9999...')
while True:
"""
接收数据:
recvfrom()方法返回数据和客户端的地址与端口,
这样,服务器收到数据后,直接调用sendto()就可以把数据用UDP发给客户端。
"""
data, addr = s.recvfrom(1024)
print('Received from %s: %s.' % (addr, data))
s.sendto(b'Hello, %s!' % data, addr)
开启服务端:
image.png
编写客户端:
import socket
# 客户端使用UDP时,首先仍然创建基于UDP的Socket,然后,不需要调用connect(),直接通过sendto()给服务器发数据
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
# 发送数据:
s.sendto(data, ('127.0.0.1', 9999))
# 接收数据:
print(s.recv(1024).decode('utf-8'))
s.close()
开启客户端:
同时服务端进行响应:
image.png
注意这里省掉了多线程,因为这个例子很简单。