c++ udp多线程 例子_[内附完整源码和文档] 基于udp实现tcp功能进行大文件传输
一.項目要求
Please choose one of following programing languages: C, C++, Java, Python;
本項目采用的是python3.6
LFTP should use a client-server service model;
本項目使用客戶端-服務(wù)器的模式
LFTP must include a client side program and a server side program; Client side program can not only send a large file to the server but also download a file from the server.
Sending file should use the following format:
LFTP lsend myserver mylargefile
Getting file should use the following format
LFTP lget myserver mylargefile
The parameter myserver can be a url address or an IP address.
本項目,客戶端不僅可以向服務(wù)器上傳大文件,也可以從服務(wù)器下載大文件
LFTP should use UDP as the transport layer protocol.
本項目利用UDP來作為傳輸層協(xié)議
LFTP must realize 100% reliability as TCP;
本項目實現(xiàn)類似TCP的100%可靠性,處理了丟包,超時,數(shù)據(jù)包順序不一致等問題
LFTP must implement flow control function similar as TCP;
本項目實現(xiàn)了類似TCP的流控制,在接收方維護一個rwnd接收窗口
LFTP must implement congestion control function similar as TCP;
本項目實現(xiàn)了類似TCP的阻塞控制,在發(fā)送方維護一個cwnd阻塞窗口
LFTP server side must be able to support multiple clients at the same time;
本項目支持多個用戶同時向服務(wù)器收發(fā)文件,使用了多線程的機制
LFTP should provide meaningful debug information when programs are
executed.
本項目提供了有意義的debug消息來顯示發(fā)送情況,包括丟包,阻塞等事件的處理
二. 設(shè)計思路
基于UDP的傳輸過程如下圖所示:
基于UDP來實現(xiàn)類似TCP的大文件傳輸,代碼構(gòu)建過程:
利用socket實現(xiàn)簡單字符串傳送
對于文件進行處理,將1的代碼改造成文件的傳送
對于文件進行分段,打包發(fā)送
發(fā)送過程使用多線程
服務(wù)器與客戶端連接的建立與斷開,三方握手,四次揮手
處理命令行輸入命令,與服務(wù)器進行交互
添加ACK反饋包,建立判斷重復(fù)ACK機制
丟包事件的判斷與處理
接收方的序列號是否正確,要求重發(fā)
接收方的流控制,構(gòu)建接收窗口
發(fā)送方的阻塞控制
三. 模塊設(shè)計
3.1 設(shè)置傳送數(shù)據(jù)包的數(shù)據(jù)結(jié)構(gòu),以及反饋包的數(shù)據(jù)結(jié)構(gòu)
這里的數(shù)據(jù)包與反饋包結(jié)構(gòu)我采用的是struct結(jié)構(gòu)體,其中一個數(shù)據(jù)包所帶有文件數(shù)據(jù)為1024bytes,而頭文件包括序列號,確認號,文件結(jié)束標志,為24bytes。
反饋包包括ack確認,rwnd接收窗口的大小。
傳送一個包的結(jié)構(gòu),包含序列號,確認號,文件結(jié)束標志,數(shù)據(jù)包
packet_struct = struct.Struct(‘III1024s’)
接收后返回的信息結(jié)構(gòu),包括ACK確認,rwnd
feedback_struct = struct.Struct(‘II’)
BUF_SIZE = 1024+24
FILE_SIZE = 1024
3.2 服務(wù)器部分:處理客戶端傳輸?shù)拿?#xff0c;并使用多線程來處理
服務(wù)器先建立一個主的線程來監(jiān)聽接收客戶端到來的命令,將命令接收后傳送到server_thread來處理,傳遞的參數(shù)包括客戶端的命令參數(shù)以及客戶端的地址。
···
IP = ‘192.168.88.129’
SERVER_PORT = 7777
···
def main():
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 綁定端口:
s.bind((IP, SERVER_PORT))
while True:
data,client_addr = s.recvfrom(BUF_SIZE)
# 多線程處理
my_thread = threading.Thread(target=server_thread,args=(client_addr,data))
my_thread.start()
3.3 服務(wù)器部分:多線程處理函數(shù)
該函數(shù)要為每一個客戶端新建一個socket,并將命令解析得到客戶端所需要的操作
def server_thread(client_addr,string):
# 處理傳輸過來的str,得到文件名,命令
order = ‘’
try:
order = string.decode(‘utf-8’).split(’,’)[0]
file_name = string.decode(‘utf-8’).split(’,’)[1]
except Exception as e:
return
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
···
除此以外,還需要像TCP建立連接一樣來進行三方握手,確認連接才開始發(fā)送。
客戶端先申請連接
三方握手
發(fā)送請求建立連接
s.sendto(data,server_addr)
接收連接允許
print(data.decode(‘utf-8’))
data,server_addr = s.recvfrom(BUF_SIZE)
print(‘來自服務(wù)器’, server_addr, '的數(shù)據(jù)是: ', data.decode(‘utf-8’))
服務(wù)器確認連接
文件存在,返回確認信號
s.sendto(‘連接就緒’.encode(‘utf-8’),client_addr)
data,client_addr = s.recvfrom(BUF_SIZE)
print(‘來自’,client_addr,‘的數(shù)據(jù)是:’,data.decode(‘utf-8’))
客戶端再發(fā)送確認包,這時連接就建立完畢
第三次握手,確認后就開始接收
data=‘ACK’.encode(‘utf-8’)
s.sendto(data,server_addr)
下面是四次揮手的過程:
當服務(wù)器執(zhí)行完客戶端的命令后,要像tcp一樣來執(zhí)行斷開連接操作,斷開連接后可以把socket釋放掉,即調(diào)用close函數(shù)。
服務(wù)器:
print(’n開始中斷連接’)
中斷連接,四次揮手
data,server_addr = s.recvfrom(BUF_SIZE)
print(data.decode(‘utf-8’))
data = ‘Server allows disconnection’
s.sendto(data.encode(‘utf-8’),client_addr)
print(data)
data = ‘Server requests disconnection’
s.sendto(data.encode(‘utf-8’),client_addr)
print(data)
data,server_addr = s.recvfrom(BUF_SIZE)
print(data.decode(‘utf-8’))
print(‘The connection between client and server has been interrupted’)
s.close()
客戶端:
中斷連接,四次揮手
data = ‘Client requests disconnection’
print(data)
s.sendto(data.encode(‘utf-8’),server_addr)
data,client_addr = s.recvfrom(BUF_SIZE)
print(data.decode(‘utf-8’))
data,client_addr = s.recvfrom(BUF_SIZE)
print(data.decode(‘utf-8’))
data = ‘Client allows disconnection’
s.sendto(data.encode(‘utf-8’),server_addr)
print(data)
print(‘The connection between client and server has been interrupted’)
s.close()
說完建立連接與斷開連接,回到多線程處理函數(shù),對于lsend,lget函數(shù)的判斷:當命令是lget時,要判斷服務(wù)器是否存在該文件,如果不存在則直接返回信息后,關(guān)閉socket;若存在該文件直接進入lget函數(shù)來進行處理。當命令是lsend時,直接進入lsend函數(shù)來進行處理。
if order == ‘lget’:
# 處理文件不存在的情況
if os.path.exists(file_name) is False:
data = ‘FileNotFound’.encode(‘utf-8’)
s.sendto(data, client_addr)
# 關(guān)閉socket
s.close()
return
# 文件存在,返回確認信號
s.sendto(‘連接就緒’.encode(‘utf-8’),client_addr)
data,client_addr = s.recvfrom(BUF_SIZE)
print(‘來自’,client_addr,‘的數(shù)據(jù)是:’,data.decode(‘utf-8’))
lget(s,client_addr,file_name)
elif order == ‘lsend’:
s.sendto(‘是否可以連接’.encode(‘utf-8’),client_addr)
# 等待確認
data,client_addr = s.recvfrom(BUF_SIZE)
print(‘來自’,client_addr,‘的數(shù)據(jù)是:’,data.decode(‘utf-8’))
lsend(s,client_addr,file_name)
完整的源碼和詳細的文檔,上傳到了 WRITE-BUG技術(shù)共享平臺 上,需要的請自取:
https://www.write-bug.com/article/2998.html
總結(jié)
以上是生活随笔為你收集整理的c++ udp多线程 例子_[内附完整源码和文档] 基于udp实现tcp功能进行大文件传输的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 台式电脑如何设置开机密码_设置苹果Mac
- 下一篇: getcwd和pwd为什么不一样_农村医