TCP和UDP的異同(含:TCP/UDP編寫的網絡聊天程序+TCP傳文件)

引言

因特網爲應用程序提供了兩個運輸層(傳輸層)協議,即TCPUDP。當我們爲因特網創建一個新的應用程序時,我們首先需要考慮的是:選擇TCP還是UDP。這兩個協議都爲調用它們的應用程序提供了不同的服務集合

 

一、TCP介紹

TCP大的服務模型包括:面向連接的服務可靠的數據傳輸服務以及擁塞控制機制

  • 面向連接的服務:在應用層的數據報文開始流動之前,先進行三次握手建立連接,即TCP讓客戶和服務器相互交換運輸層的控制信息。
  • 可靠的數據傳輸服務:不同的主機間的不同進程間能夠依靠TCP進行無差錯按適當順序交付所有發送的數據。
  • 擁塞控制機制:當發送方和接收方之間的網絡出現擁塞時,TCP的擁塞控制機制會抑制發送進程(客戶/服務器);TCP擁塞控制機制也試圖限制每個TCP連接,使它們達到公平共享網絡帶寬的目的。

 

二、UDP介紹

UDP是一種不提供不必要(no-frills)服務的輕量級運輸協議,它僅提供最小的服務。UDP是無連接的,因此在兩個進程通信前沒有握手的過程。UDP協議提供一種不可靠數據傳輸服務,也就是說,當進程將一個報文發送進UDP套接字時,UDP協議並不保證該報文將到達接收進程。不僅如此,到達接收進程的報文也可能是亂序的。

UDP也沒有擁塞控制機制,所以UDP的發送端可以用它選定的任何速率向其下層(網絡層)注入數據。

 

三、拓展(TCP加強版:SSL)

TCP/UDP都沒有提供任何加密機制,因此因特網界提供了一個在應用層上實現的加強版的TCP,叫作:安全套接字層(Secure Sockets Layer, SSL)。

 

四、TCP與UDP的比較

1、連接:TCP面向連接;UDP是無連接的。

2、可靠:TCP提供可靠傳輸服務:無差錯、按序到達;UDP盡力而爲,不提供可靠傳輸。

3、實時性:UDP有較好的實時性,效率比TCP高。

4、擁塞控制:TCP有擁塞控制機制;UDP無擁塞控制機制。

5、資源:TCP對系統資源要求多;UDP對系統資源要求少。

 

五、使用TCP/UDP編寫網絡聊天程序

UDP:

# Client.py
import socket
import time, threading
# 創建套接字,參數1:指示了地址簇,IF_INEF指示了底層使用IPv4;
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

def tcplink():
    while True:
        js = input('我:')
        s.sendto(js.encode('utf-8'), ('127.0.0.1', 9994))   

        data = s.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            print('Connection closed.')
            break
        print(('東方不敗:%s' % data.decode('utf-8'))+ '         ' + time.strftime("%H:%M:%S"))  
    s.close()
t = threading.Thread(target=tcplink, args=())
t.start()
# Server.py
import socket
import time, threading
import os
# 創建了一個socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 監聽端口
s.bind(('127.0.0.1', 9994))

print('Waiting for connection...')

while True:
    message, clientAddress = s.recvfrom(2048)
    time.sleep(1)
    if message.decode('utf-8') == 'exit':
            break
    print(message.decode('utf-8'))
    js = input('我:')
    s.sendto(js.encode('utf-8'), clientAddress)

TCP:聊天+傳文件(附加進度條)

# TCPClient.py
import socket
import time, threading
import os
import struct
import sys
import json
from processbar import process_bar
buffsize = 1024
# 創建了一個socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 監聽端口
s.bind(('127.0.0.1', 9994))
# 調用listen()方法開始監聽端口
s.listen(5)
print('Waiting for connection...')

# 接收文件函數
def recvfile(sock):
    # 接收報文的長度
    head_struct = sock.recv(4)
    if head_struct:
        print('等待接收數據:')
    # 解析出報頭的字符串大小
    head_len = struct.unpack('i', head_struct)[0]
    #print(head_len)
    # 接收長度爲head_len的報頭內容信息(包含文件大小,文件名的內容)
    data = sock.recv(head_len)
    head_dir = json.loads(data.decode('utf-8'))
    filesize_b = head_dir['filesize_bytes']
    filename = head_dir['filename']
    # 接收真實的文件內容
    recv_len = 0
    recv_mesg = b''
    old = time.time()
    f = open(filename, 'wb')
    while recv_len < filesize_b:
        percent = recv_len / filesize_b
        process_bar(percent)
        if(filesize_b - recv_len > buffsize):
            recv_mesg = sock.recv(buffsize)
            f.write(recv_mesg)
            recv_len += len(recv_mesg)
        else:
            recv_mesg = sock.recv(filesize_b - recv_len)
            recv_len += len(recv_mesg)
            f.write(recv_mesg)
    print(recv_len, filesize_b)
    now = time.time()
    stamp = int(now - old)
    print('接收成功,總共用時%ds' % stamp)
    f.close()
    
# 對每個連接的客戶端所做的處理
def tcplink(sock, addr):
    # print('Accept new connection from %s%s...' % addr)
    # sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        # 若接收到sendfile則調用接受文件函數,接收成功後進入下一輪
        if(data.decode('utf-8') == 'sendfile'):
            recvfile(sock)
            continue
    
        if not data or data.decode('utf-8') == 'exit':
            break
        print(('西門吹雪:%s' % data.decode('utf-8')) + '         ' + time.strftime("%H:%M:%S"))
        js = input('我:')
        sock.send(js.encode('utf-8'))
        # sock.send(('Hello, %s' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s%s closed.' % addr)

# 接下來服務器通過一個永久循環來接受來自客戶端的連接, accept()會等待並返回一個客戶端的連接
while True:
    # 接受一個新連接
    sock, addr = s.accept()
    # 創建新線程來處理TCP連接
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()


# TCPClient.py
import socket
import time, threading
import struct
import json
import os
# 創建套接字,參數1:指示了地址簇,IF_INEF指示了底層使用IPv4;參數2:表明創建了一個TCP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 建立連接
s.connect(('127.0.0.1', 9994))

# 發送文件的函數
def file_process():
    filemesg = input('請輸入傳送的文件名>>>').strip()
    # 獲取文件的大小(字節)
    filesize_bytes = os.path.getsize(filemesg)
    # 發送文件重命名
    filename = 'new' + filemesg 
    dirc = {
        'filename' : filename,
        'filesize_bytes' : filesize_bytes,
    }
    # 將字典轉換爲字符串
    head_info = json.dumps(dirc) 
    # 將字符串的長度打包
    head_info_len =  struct.pack('i', len(head_info))
    # 發送head_info的長度
    s.send(head_info_len)
    # 發送head_info
    s.send(head_info.encode('utf-8'))
    # 發送真實的文件信息
    with open(filemesg, 'rb') as f:
        data = f.read()
        s.sendall(data)
    print('發送成功')

# 接收消息的函數
def tcplink():
    while True:
        js = input('我:')
        s.send(js.encode('utf-8'))
        # 假如是sendfile則調用發送文件函數,待發送成功後重新進入下一輪
        if(js == 'sendfile'):
            file_process() 
            continue

        data = s.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            print('Connection closed.')
            break
        print(('東方不敗:%s' % data.decode('utf-8'))+ '         ' + time.strftime("%H:%M:%S"))  
    s.close()

# 創建一個線程用來用於和服務器建立連接
t = threading.Thread(target=tcplink, args=())
t.start()

# processbar.py
# 進度條顯示代碼
import sys
import time
def process_bar(precent, width = 50):
    use_num = int(precent*width)
    space_num = int(width-use_num)
    precent = precent*100
    print('[%s%s]%d%%' % (use_num*'#', space_num*' ', precent), file=sys.stdout, flush=True, end='\r')

參考博文:

1、https://blog.csdn.net/xiaobangkuaipao/article/details/76793702

2、https://www.cnblogs.com/xiaomayizoe/p/5258754.html

3、https://www.cnblogs.com/HPAHPA/p/7737641.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章