TCP和UDP编程
此博客链接:https://www.cnblogs.com/ping2yingshi/p/14388417.html
1.UDP编程
1.1说明
1.名字
客户端名字:UDPClient
服务器名字:UDPServer
2.运行环境
Python 3.8.5
3.通信过程
UDP连接时,需要先开启服务端,客户端向服务端发送数据前,双方先创建套接字,创建完套接字之后,双方进入到数据收发阶段,最后通信结束。
1.2代码
1.2.1说明
1.2.1.1UDPClient
1.socket 建立UDP的套接字。
2.clientSocket.sendto()向UDP服务端发送数据。
3.SOCK_DGRAM 代表 UDP连接。
1.2.1.2UDPServer
1.serverSocket.bind()将IP地址,端口号与服务端的套接字绑定。
2.message,clientAddress=serverSocket.recvfrom(1024)
1.2.2UDPClient
import socket
BUFSIZE = 1024
#创建套接字
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_port = ('127.0.0.1', 8081)
while True:
# 获取用户输入
msg = input(">> ").strip()
# 向服务端发送用户数据
client.sendto(msg.encode('utf-8'), ip_port)
# 接收对方发送过来的数据,最大接收1024个字节
data, server_addr = client.recvfrom(BUFSIZE)
print('客户端recvfrom ', data, server_addr)
client.close()
1.2.3UDPServer
import socket
BUFSIZE = 1024
ip_port = ('127.0.0.1', 8081)
#创建套接字
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp协议
#绑定IP和端口号
server.bind(ip_port)
while True:
# 接收对方发送过来的数据,最大接收1024个字节
data, client_addr = server.recvfrom(BUFSIZE)
print('server收到的数据', data)
# 向客户端发送服务端数据
server.sendto("thank you !".encode('utf8'), client_addr)
server.close()
1.3实验过程
1.先运行UDPServer.py,打开服务端。
2.再运行UDPClient.py,打开客服端,输入123。
3.在服务器端接收到123数据。
4.动图展示
打开UDPServer后,再打开UDPClient并输入123,在UDPServer收到123。
1.4通信过程
1.4.1说明
抓包工具:Wireshark
1.4.2过程
1.客户端client 发送数据
2.服务端server接收数据
3.抓包数据
wireshark 设置过滤UDP抓包参数为:"udp.port==8081",(代码udp 服务端设置绑定端口号为8081)
根据上图可知:UDP的端口号为8081。
第一条数据是客户端向服务器发送字节长度为2的"YP"数据。
第二条数据是服务器收到客户端发送的数据并向客服端发送长度为11的“thank you!”数据。
第三条数据是客户端向服务器发送字节长度为5的"nihao"数据。
第四条数据是服务器收到客户端发送的数据并向客服端发送长度为11的“thank you!”数据。
2.TCP编程
2.1说明
1.名字
客户端名字:TCPClient
服务器名字:TCPServer
2.运行环境
Python 3.8.5
3.通信过程
TCP连接时,需要先开启服务端,客户端向服务端发送数据前,双方先创建套接字,创建完套接字之后,客户端会向服务器发起连接操作,连接操作完成后,双方进入到数据收发阶段,最后客户端先发起断开连接诶,服务端随后断开连接。
2.2代码
2.2.1说明
2.2.1.1TCPClient
1.创建客户端socket套接字
2.客户端套接字主动连接服务端套接字(提供服务端套接字绑定的ip和端口号)
3.客户端套接字向服务端套接字发送数据
2.2.1.2TCPServer
1.创建socket套接字
2.给socket绑定ip和端口号
3.开始 TCP 监听,等待客户端连接
4.服务端接收并处理客户端发送的数据
2.2.2TCPClient
from socket import * from pip._vendor.distlib.compat import raw_input #目的信息 serverName ='localhost' serverPort =14000 #创建套接字 clientSocket =socket(AF_INET,SOCK_STREAM) #建立连接 clientSocket.connect((serverName,serverPort)) #获取用户输入 sentence =raw_input('Input lowercase sentence:') #向服务端发送用户数据 clientSocket.send(bytes(sentence,encoding='utf8')) # 接收对方发送过来的数据,最大接收1024个字节 modifiedSentence=clientSocket.recv(1024); print ('From Server:',modifiedSentence)
clientSocket.close()
2.2.3TCPServer
from socket import * from pip._vendor.distlib.compat import raw_input #本地信息 serverName ='localhost' serverPort =14000 #创建套接字 serverSocket =socket(AF_INET,SOCK_STREAM) serverSocket.bind((serverName,serverPort)) print("This server is ready to receive") #监听来自客户端的TCP链接 serverSocket.listen(serverPort) while True: #创建新的套接字 connectionSocket=serverSocket.accept() # 接收对方发送过来的数据,最大接收2048个字节 sentence=connectionSocket.recvfrom(2048) #获取由客户发送的行并使用upper()方法将其转换为大写 capitalizedSentence=sentence.upper() if sentence: print("接受到的数据是:",sentence) #向客户端发送数据 connectionSocket.send(capitalizedSentence) #关闭连接 connectionSocket.close()
2.3实验过程
1.先运行TCPServer.py,打开服务端,当运行程序时,程序报错,显示无法连接。
2.查阅资料,在accept之前,应该打开listen进行监听。
3.再次运行TCPServer.py,打开了服务端。
4.运行TCPClient.py,打开客户端,发送数据123,显示主机的软件中止了一个已建立的连接。
5.修改错误
(1)TCPServer中的recvfrom修改成recv,recvfrom是UDP中的通信。
(2)接收套接字时,根据python语法,需要把元组中的所有元素都获取,添加clientAddr=serverSocket.accept()语句
accept函数返回元组。
6.正确代码
(1)TCPServer
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 文件名:tcp-server.py
from socket import *
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 本地信息
address = ('localhost', 8080)
# 绑定
tcp_server_socket.bind(address)
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的连接了
# listen里的数字表征同一时刻能连接客户端的程度.
tcp_server_socket.listen(5)
print("This server is ready to receive")
while True:
# 如果有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务
# client_socket用来为这个客户端服务
# tcp_server_socket就可以省下来专门等待其他新客户端的连接
# clientAddr 是元组(ip,端口)
client_socket, clientAddr = tcp_server_socket.accept()
print("client连接地址信息为:", clientAddr)
# 接收对方发送过来的数据,和udp不同返回的只有数据
recv_data = client_socket.recv(1024) # 接收1024个字节
print('server接收到的数据为:', recv_data.decode('utf8'))
# 发送一些数据到客户端
client_socket.send("thank you !".encode('utf8'))
# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
client_socket.close()
(2)TCPClient
#!/usr/bin/python # -*- coding: UTF-8 -*- # 文件名:tcp-client.py from socket import * # 创建socket tcp_client_socket = socket(AF_INET, SOCK_STREAM) # 目的信息 server_ip = 'localhost' server_port = 8080 # 连接服务器 tcp_client_socket.connect((server_ip, server_port)) # while True: # 提示用户输入数据 send_data = input("请输入client要发送的数据:") # 发送数据 tcp_client_socket.send(send_data.encode("utf8")) # 接收对方发送过来的数据,最大接收1024个字节 recvData = tcp_client_socket.recv(1024) print('client接收到的数据为:', recvData.decode('utf8')) # 关闭套接字 tcp_client_socket.close()
7.动图展示
打开TCPServer后,再打开TCPClient并输入123,在TCPServer收到123。
2.4通信过程
2.4.1说明
抓包工具:Wireshark
2.4.2过程
1.客户端client 发送数据
2.服务端server接收数据,其中客户端地址显示端口号为56070
3.抓包数据
wireshark 设置过滤TCP抓包参数为:"tcp.port==8080",(代码tcp 服务端设置绑定端口号为8080)
根据上图可知:图中前三条数据是客户端向服务端发起连接操作。
第一条数据表示:客户端生成一个SYN为1的TCP包并发送给服务器。这个TCP包的头部还包含了客户端发送数据时需要用到的窗口大小8192。
第二条数据表示:当这个包到达服务器之后,服务器会返回一个SYN为1的TCP包。这个包也包含了序号和窗口大小,还包含了表示确认已经收到包的ACK号。
第三条数据表示:客户端向服务器返回一个包表示确认的ACK号的TCP包。
图中的中间四条数据是客户端和服务端发送数据过程。
第一条数据是客户端向服务器发送数据"yp"字节长度为2并返回一个包表示确认的ACK。
第二条数据是服务器收到客户端发送的数据并返回ACK=3的确认包。
第三条数据是服务端向客户端发送的数据"thank you !"字节长度为11并返回ACK=3的包。
第四条数据是客户端接收到服务端的数据并返回ACK=12的包。
图中最后四条数据是客户端和服务端关闭连接。
第一条数据是服务端向客户端发送FIN,表示服务端没有数据要发送给客户端了。
第二条是客户端接收到服务端的FIN报文段,向服务端发送一个ACK报文段。
第三条是客户端向服务端发送FIN,请求关闭连接。
第四条是服务端接收到客户端发送的FIN报文段,向客户端发送ACK报文段,至此客户端和服务端关闭连接。