1.TCP
TCP通信模型中,在通信开始之前,⼀定要先建⽴相关的连接,才能发送数据,类似于⽣活中,"打电话"。TCP编程分为客户端和服务器端两部分组成,所以我们需要首先完成服务器端的编程,之后完成客户端的编程,再使用客户端连接服务器端。
TCP是有状态的,安全的,可靠的,有连接的协议。TCP建立连接时,要经过三次握手,连接断开时要经过四次挥手。在未连接时,服务器等待客户端的连接,当客户端连接上时,向客户端发送输入的信息。
2.TCP服务器的搭建流程
(1)、socket创建⼀个套接字; (2)、bind绑定ip和port;(3)、listen使套接字变为可以被动链接;(4)、accept等待客户端的链接;(5)、recv/send接收发送数据。
import socket
import time
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server.bind(("", 8080))
# 表示监听的数量 在Linux下是无效的
server.listen(10)
print("服务器开始监听了……")
# 等待客户端的连接 返回的是一个元组包含客户端对象和它的套接字 这个客户端对象用于向客户端发送信息
# 其中laddr ===>local address raddr ===>remote address
data = server.accept()
server.send()
# print(data)
time.sleep(10)
# 关闭服务器
server.close()
用网络调试助手连接后返回如下结果
服务器开始监听了……
(<socket.socket fd=440, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.14.30', 8080), raddr=('192.168.14.30', 51853)>, ('192.168.14.30', 51853))
3.服务器端发送数据和接受数据
服务器端
import socket
import time
# 获取一个基于TCP协议的socket对象
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server.bind(("", 8080))
# 表示监听的数量 在Linux下是无效的
server.listen(10)
print("服务器开始监听了……")
client_socket, client_address = server.accept()
client_socket.send("本服务器来自于阎王殿,告诉你一个不幸的消息,你命不久矣".encode("utf-8"))
msg = client_socket.recv(1024).decode("utf-8")
print("收到来自于{} {}客户端的信息:".format(client_address[0], client_address[1]), msg)
# print(data)
time.sleep(10)
# 关闭服务器
server.close()
客户端
import socket
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
try:
print("客户端开始连接了……")
client.connect(("192.168.14.30", 8080))
print("连接成功")
msg = client.recv(1024).decode("utf-8")
print("收到来自于服务器{} {}的信息:".format("192.168.14.30", 8080), msg)
client.send("怎么可能,我堂堂大罗金仙,寿命永恒,怎会死亡".encode("utf-8"))
except Exception as e:
print("连接失败,错误信息是", e)
finally:
client.close()
客户端连接上服务器时,客户端输出信息如下:
客户端开始连接了……
连接成功
收到来自于服务器192.168.14.30 8080的信息: 本服务器来自于阎王殿,告诉你一个不幸的消息,你命不久矣
服务器端输出信息如下:
服务器开始监听了……
收到来自于192.168.14.30 50805客户端的信息: 怎么可能,我堂堂大罗金仙,寿命永恒,怎会死亡
当客户端断开后,服务器端会报错,这需要抛出错误,让程序正常结束
4.多线程的实现
服务器端
def main():
import socket
from threading import Thread
server = socket.socket()
server.bind(("", 8080))# 绑定服务器的ip 当然也可将服务器的套接字当成一个参数传入
server.listen(10)
socket_client, socket_address = server.accept()
socket_client.send("你已连接到服务器,请注意您的言谈举止".encode("utf-8"))
t1 = Thread(target=send_msg, args=[socket_client])
t2 = Thread(target=rec_msg, args=[socket_client])
t1.start()
t2.start()
server.close()
def send_msg(client):
try:
while True:
client.send("\n".encode("utf-8"))
client.send(input("").encode("utf-8"))
except Exception as e:
print("退出连接")
finally:
close_resource(client)
def rec_msg(client):
try:
while True:
print(client.recv(1024).decode("utf-8"))
except Exception as e:
print("退出连接")
finally:
close_resource(client)
def close_resource(client):
if client is not None:
client.close()
客户端
# 传入服务器的套接字
def main(ip):
import socket
from threading import Thread
client = socket.socket()
client.connect(ip)
print("连接成功")
print(">:", client.recv(1024).decode("utf-8"))
t1 = Thread(target=send_msg, args=[client])
t2 = Thread(target=rec_msg, args=[client])
t1.start()
t2.start()
def send_msg(client):
try:
while True:
client.send("\n".encode("utf-8"))
client.send(input("").encode("utf-8"))
except Exception as e:
print("退出连接")
finally:
close_resource(client)
def rec_msg(client):
try:
while True:
print(client.recv(1024).decode("utf-8"))
except Exception as e:
print("退出连接")
finally:
close_resource(client)
def close_resource(client):
if client is not None:
client.close()
main(("192.168.14.30", 8080))
由于客户端的退出会导致服务器端出错这里做了抛出错误的处理。