日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

27 网络通信协议 udp tcp

發(fā)布時(shí)間:2023/12/13 综合教程 26 生活家
生活随笔 收集整理的這篇文章主要介紹了 27 网络通信协议 udp tcp 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

四 網(wǎng)絡(luò)通信協(xié)議(互聯(lián)網(wǎng)協(xié)議)

第二天再講這里,大家第二天再看這里把~~~

網(wǎng)絡(luò)通信協(xié)議是網(wǎng)絡(luò)傳輸?shù)撵`魂,非常重要,協(xié)議即準(zhǔn)則,準(zhǔn)則是傳輸消息的格式要求,那么我們從電腦上發(fā)出一個(gè)消息,到底是以什么樣的消息格式發(fā)到了對(duì)方的手上呢,來看一看這里>>>,網(wǎng)絡(luò)通信協(xié)議

五 osi七層模型

互聯(lián)網(wǎng)的核心就是由一堆協(xié)議組成,協(xié)議就是標(biāo)準(zhǔn),標(biāo)準(zhǔn)就是大家都認(rèn)可的,所有人都按照這個(gè)來,這樣大家都能夠互相了解,互相深入了~~~比如全世界人通信的標(biāo)準(zhǔn)是英語

五層通信流程:

六 socket

結(jié)合上圖來看,socket在哪一層呢,我們繼續(xù)看下圖

socket在內(nèi)的五層通訊流程:

Socket又稱為套接字,它是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層,它是一組接口。在設(shè)計(jì)模式中,Socket其實(shí)就是一個(gè)門面模式,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面,對(duì)用戶來說,一組簡(jiǎn)單的接口就是全部,讓Socket去組織數(shù)據(jù),以符合指定的協(xié)議。當(dāng)我們使用不同的協(xié)議進(jìn)行通信時(shí)就得使用不同的接口,還得處理不同協(xié)議的各種細(xì)節(jié),這就增加了開發(fā)的難度,軟件也不易于擴(kuò)展(就像我們開發(fā)一套公司管理系統(tǒng)一樣,報(bào)賬、會(huì)議預(yù)定、請(qǐng)假等功能不需要單獨(dú)寫系統(tǒng),而是一個(gè)系統(tǒng)上多個(gè)功能接口,不需要知道每個(gè)功能如何去實(shí)現(xiàn)的)。于是UNIX BSD就發(fā)明了socket這種東西,socket屏蔽了各個(gè)協(xié)議的通信細(xì)節(jié),使得程序員無需關(guān)注協(xié)議本身,直接使用socket提供的接口來進(jìn)行互聯(lián)的不同主機(jī)間的進(jìn)程的通信。這就好比操作系統(tǒng)給我們提供了使用底層硬件功能的系統(tǒng)調(diào)用,通過系統(tǒng)調(diào)用我們可以方便的使用磁盤(文件操作),使用內(nèi)存,而無需自己去進(jìn)行磁盤讀寫,內(nèi)存管理。socket其實(shí)也是一樣的東西,就是提供了tcp/ip協(xié)議的抽象,對(duì)外提供了一套接口,同過這個(gè)接口就可以統(tǒng)一、方便的使用tcp/ip協(xié)議的功能了。

其實(shí)站在你的角度上看,socket就是一個(gè)模塊。我們通過調(diào)用模塊中已經(jīng)實(shí)現(xiàn)的方法建立兩個(gè)進(jìn)程之間的連接和通信。也有人將socket說成ip+port,因?yàn)閕p是用來標(biāo)識(shí)互聯(lián)網(wǎng)中的一臺(tái)主機(jī)的位置,而port是用來標(biāo)識(shí)這臺(tái)機(jī)器上的一個(gè)應(yīng)用程序。 所以我們只要確立了ip和port就能找到一個(gè)應(yīng)用程序,并且使用socket模塊來與之通信

七 套接字socket的發(fā)展史及分類

套接字起源于 20 世紀(jì) 70 年代加利福尼亞大學(xué)伯克利分校版本的 Unix,即人們所說的 BSD Unix。 因此,有時(shí)人們也把套接字稱為“伯克利套接字”或“BSD 套接字”。一開始,套接字被設(shè)計(jì)用在同 一臺(tái)主機(jī)上多個(gè)應(yīng)用程序之間的通訊。這也被稱進(jìn)程間通訊,或 IPC。套接字有兩種(或者稱為有兩個(gè)種族),分別是基于文件型的和基于網(wǎng)絡(luò)型的。

基于文件類型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字調(diào)用的就是底層的文件系統(tǒng)來取數(shù)據(jù),兩個(gè)套接字進(jìn)程運(yùn)行在同一機(jī)器,可以通過訪問同一個(gè)文件系統(tǒng)間接完成通信

基于網(wǎng)絡(luò)類型的套接字家族

套接字家族的名字:AF_INET

(還有AF_INET6被用于ipv6,還有一些其他的地址家族,不過,他們要么是只用于某個(gè)平臺(tái),要么就是已經(jīng)被廢棄,或者是很少被使用,或者是根本沒有實(shí)現(xiàn),所有地址家族中,AF_INET是使用最廣泛的一個(gè),python支持很多種地址家族,但是由于我們只關(guān)心網(wǎng)絡(luò)編程,所以大部分時(shí)候我們只使用AF_INET)

八 基于TCP和UDP兩個(gè)協(xié)議下socket的通訊流程

1.TCP和UDP對(duì)比

TCP(Transmission Control Protocol)可靠的、面向連接的協(xié)議(eg:打電話)、傳輸效率低全雙工通信(發(fā)送緩存&接收緩存)、面向字節(jié)流。使用TCP的應(yīng)用:Web瀏覽器;文件傳輸程序。

UDP(User Datagram Protocol)不可靠的、無連接的服務(wù),傳輸效率高(發(fā)送前時(shí)延小),一對(duì)一、一對(duì)多、多對(duì)一、多對(duì)多、面向報(bào)文(數(shù)據(jù)包),盡最大努力服務(wù),無擁塞控制。使用UDP的應(yīng)用:域名系統(tǒng) (DNS);視頻流;IP語音(VoIP)。

直接看圖對(duì)比其中差異

 

繼續(xù)往下看

TCP和UDP下socket差異對(duì)比圖:

上面的圖只是讓大家感受一下TCP和UDP協(xié)議下,socket工作流程的不同,兩者之間的差異是tcp需要連接,udp不需要,有些同學(xué)是不是有些迷糊,老師,這里面的bind、listen啥的都是什么東西啊,我感覺人生是迷茫的!calm down!下面我們就分開兩者,細(xì)細(xì)學(xué)習(xí)!

2.TCP協(xié)議下的socket

來吧!先上圖!

基于TCP的socket通訊流程圖片:

雖然上圖將通訊流程中的大致描述了一下socket各個(gè)方法的作用,但是還是要總結(jié)一下通訊流程(下面一段內(nèi)容)

先從服務(wù)器端說起。服務(wù)器端先初始化Socket,然后與端口綁定(bind),對(duì)端口進(jìn)行監(jiān)聽(listen),調(diào)用accept阻塞,等待客戶端連接。在這時(shí)如果有個(gè)客戶端初始化一個(gè)Socket,然后連接服務(wù)器(connect),如果連接成功,這時(shí)客戶端與服務(wù)器端的連接就建立了。客戶端發(fā)送數(shù)據(jù)請(qǐng)求,服務(wù)器端接收請(qǐng)求并處理請(qǐng)求,然后把回應(yīng)數(shù)據(jù)發(fā)送給客戶端,客戶端讀取數(shù)據(jù),最后關(guān)閉連接,一次交互結(jié)束

上代碼感受一下,需要?jiǎng)?chuàng)建兩個(gè)文件,文件名稱隨便起,為了方便看,我的兩個(gè)文件名稱為tcp_server.py(服務(wù)端)和tcp_client.py(客戶端),將下面的server端的代碼拷貝到tcp_server.py文件中,將下面client端的代碼拷貝到tcp_client.py的文件中,然后先運(yùn)行tcp_server.py文件中的代碼,再運(yùn)行tcp_client.py文件中的代碼,然后在pycharm下面的輸出窗口看一下效果。

server端代碼示例(如果比喻成打電話)

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8898))  #把地址綁定到套接字
sk.listen()          #監(jiān)聽鏈接
conn,addr = sk.accept() #接受客戶端鏈接
ret = conn.recv(1024)  #接收客戶端信息
print(ret)       #打印客戶端信息
conn.send(b'hi')        #向客戶端發(fā)送信息
conn.close()       #關(guān)閉客戶端套接字
sk.close()        #關(guān)閉服務(wù)器套接字(可選)

tcp_server.py

View Code

client端代碼示例

import socket
sk = socket.socket()           # 創(chuàng)建客戶套接字
sk.connect(('127.0.0.1',8898))    # 嘗試連接服務(wù)器
sk.send(b'hello!')
ret = sk.recv(1024)         # 對(duì)話(發(fā)送/接收)
print(ret)
sk.close()            # 關(guān)閉客戶套接字

tcp_client.py

View Code

socket綁定IP和端口時(shí)可能出現(xiàn)下面的問題:

    解決辦法: 

#加入一條socket配置,重用ip和端口
import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #在bind前加,允許地址重用
sk.bind(('127.0.0.1',8898))  #把地址綁定到套接字
sk.listen()          #監(jiān)聽鏈接
conn,addr = sk.accept() #接受客戶端鏈接
ret = conn.recv(1024)   #接收客戶端信息
print(ret)              #打印客戶端信息
conn.send(b'hi')        #向客戶端發(fā)送信息
conn.close()       #關(guān)閉客戶端套接字
sk.close()        #關(guān)閉服務(wù)器套接字(可選)

解決辦法

View Code

但是如果你加上了上面的代碼之后還是出現(xiàn)這個(gè)問題:OSError: [WinError 10013] 以一種訪問權(quán)限不允許的方式做了一個(gè)訪問套接字的嘗試。那么只能換端口了,因?yàn)槟愕碾娔X不支持端口重用。

    記住一點(diǎn),用socket進(jìn)行通信,必須是一收一發(fā)對(duì)應(yīng)好。

關(guān)于setsockopt可以看這篇文章。關(guān)于setsockopt的使用

  提一下:網(wǎng)絡(luò)相關(guān)或者需要和電腦上其他程序通信的程序才需要開一個(gè)端口。

  

  在看UDP協(xié)議下的socket之前,我們還需要加一些內(nèi)容來講:看代碼

    server端

import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
# sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 
sk.bind(('127.0.0.1',8090))
sk.listen()
conn,addr = sk.accept()  #在這阻塞,等待客戶端過來連接
while True:
    ret = conn.recv(1024)  #接收消息  在這還是要阻塞,等待收消息
    ret = ret.decode('utf-8')  #字節(jié)類型轉(zhuǎn)換為字符串中文
    print(ret)
    if ret == 'bye':        #如果接到的消息為bye,退出
        break
    msg = input('服務(wù)端>>')  #服務(wù)端發(fā)消息
    conn.send(msg.encode('utf-8'))
    if msg == 'bye':
        break

conn.close()
sk.close()

只能與第一個(gè)客戶端通信server端代碼

View Code

    client端

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8090)) #連接服務(wù)端

while True:
    msg = input('客戶端>>>')  #input阻塞,等待輸入內(nèi)容
    sk.send(msg.encode('utf-8'))
    if msg == 'bye':
        break
    ret = sk.recv(1024)
    ret = ret.decode('utf-8')
    print(ret)
    if ret == 'bye':
        break
sk.close()

只能與第一個(gè)客戶端通信client端代碼

View Code

 你會(huì)發(fā)現(xiàn),第一個(gè)連接的客戶端可以和服務(wù)端收發(fā)消息,但是第二個(gè)連接的客戶端發(fā)消息服務(wù)端是收不到的

  原因解釋:
    tcp屬于長(zhǎng)連接,長(zhǎng)連接就是一直占用著這個(gè)鏈接,這個(gè)連接的端口被占用了,第二個(gè)客戶端過來連接的時(shí)候,他是可以連接的,但是處于一個(gè)占線的狀態(tài),就只能等著去跟服務(wù)端建立連接,除非一個(gè)客戶端斷開了(優(yōu)雅的斷開可以,如果是強(qiáng)制斷開就會(huì)報(bào)錯(cuò),因?yàn)榉?wù)端的程序還在第一個(gè)循環(huán)里面),然后就可以進(jìn)行和服務(wù)端的通信了。什么是優(yōu)雅的斷開呢?看代碼。
server端代碼:

import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
# sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #允許地址重用,這個(gè)東西都說能解決問題,我非常不建議大家這么做,容易出問題
sk.bind(('127.0.0.1',8090))
sk.listen()
# 第二步演示,再加一層while循環(huán)
while True:    #下面的代碼全部縮進(jìn)進(jìn)去,也就是循環(huán)建立連接,但是不管怎么聊,只能和一個(gè)聊,也就是另外一個(gè)優(yōu)雅的斷了之后才能和另外一個(gè)聊
                #它不能同時(shí)和好多人聊,還是長(zhǎng)連接的原因,一直占用著這個(gè)端口的連接,udp是可以的,然后我們學(xué)習(xí)udp
    conn,addr = sk.accept()  #在這阻塞,等待客戶端過來連接
    while True:
        ret = conn.recv(1024)  #接收消息  在這還是要阻塞,等待收消息
        ret = ret.decode('utf-8')  #字節(jié)類型轉(zhuǎn)換為字符串中文
        print(ret)
        if ret == 'bye':        #如果接到的消息為bye,退出
            break
        msg = input('服務(wù)端>>')  #服務(wù)端發(fā)消息
        conn.send(msg.encode('utf-8'))
        if msg == 'bye':
            break
    conn.close()

優(yōu)雅的斷開一個(gè)client端之后另一個(gè)client端就可以通信的代碼

View Code

client端代碼

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8090)) #連接服務(wù)端

while True:
    msg = input('客戶端>>>')  #input阻塞,等待輸入內(nèi)容
    sk.send(msg.encode('utf-8'))
    if msg == 'bye':
        break
    ret = sk.recv(1024)
    ret = ret.decode('utf-8')
    print(ret)
    if ret == 'bye':
        break
# sk.close()

client端代碼

View Code

  強(qiáng)制斷開連接之后的報(bào)錯(cuò)信息:

    

3.UDP協(xié)議下的socket

老樣子!先上圖!

基于UDP的socket通訊流程:

總結(jié)一下UDP下的socket通訊流程

  先從服務(wù)器端說起。服務(wù)器端先初始化Socket,然后與端口綁定(bind),recvform接收消息,這個(gè)消息有兩項(xiàng),消息內(nèi)容和對(duì)方客戶端的地址,然后回復(fù)消息時(shí)也要帶著你收到的這個(gè)客戶端的地址,發(fā)送回去,最后關(guān)閉連接,一次交互結(jié)束

上代碼感受一下,需要?jiǎng)?chuàng)建兩個(gè)文件,文件名稱隨便起,為了方便看,我的兩個(gè)文件名稱為udp_server.py(服務(wù)端)和udp_client.py(客戶端),將下面的server端的代碼拷貝到udp_server.py文件中,將下面cliet端的代碼拷貝到udp_client.py的文件中,然后先運(yùn)行udp_server.py文件中的代碼,再運(yùn)行udp_client.py文件中的代碼,然后在pycharm下面的輸出窗口看一下效果。

server端代碼示例

import socket
udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #創(chuàng)建一個(gè)服務(wù)器的套接字
udp_sk.bind(('127.0.0.1',9000))        #綁定服務(wù)器套接字
msg,addr = udp_sk.recvfrom(1024)
print(msg)
udp_sk.sendto(b'hi',addr)                 # 對(duì)話(接收與發(fā)送)
udp_sk.close()                         # 關(guān)閉服務(wù)器套接字

udp_server.py

View Code

client端代碼示例

import socket
ip_port=('127.0.0.1',9000)
udp_sk=socket.socket(type=socket.SOCK_DGRAM)
udp_sk.sendto(b'hello',ip_port)
back_msg,addr=udp_sk.recvfrom(1024)
print(back_msg.decode('utf-8'),addr)

View Code

類似于qq聊天的代碼示例:

#_*_coding:utf-8_*_
import socket
ip_port=('127.0.0.1',8081)
udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #DGRAM:datagram 數(shù)據(jù)報(bào)文的意思,象征著UDP協(xié)議的通信方式
udp_server_sock.bind(ip_port)#你對(duì)外提供服務(wù)的端口就是這一個(gè),所有的客戶端都是通過這個(gè)端口和你進(jìn)行通信的

while True:
    qq_msg,addr=udp_server_sock.recvfrom(1024)# 阻塞狀態(tài),等待接收消息
    print('來自[%s:%s]的一條消息:33[1;44m%s33[0m' %(addr[0],addr[1],qq_msg.decode('utf-8')))
    back_msg=input('回復(fù)消息: ').strip()

    udp_server_sock.sendto(back_msg.encode('utf-8'),addr)

server端

View Code

#_*_coding:utf-8_*_
import socket
BUFSIZE=1024
udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

qq_name_dic={
    'taibai':('127.0.0.1',8081),
    'Jedan':('127.0.0.1',8081),
    'Jack':('127.0.0.1',8081),
    'John':('127.0.0.1',8081),
}


while True:
    qq_name=input('請(qǐng)選擇聊天對(duì)象: ').strip()
    while True:
        msg=input('請(qǐng)輸入消息,回車發(fā)送,輸入q結(jié)束和他的聊天: ').strip()
        if msg == 'q':break
        if not msg or not qq_name or qq_name not in qq_name_dic:continue
        udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])# 必須帶著自己的地址,這就是UDP不一樣的地方,不需要建立連接,但是要帶著自己的地址給服務(wù)端,否則服務(wù)端無法判斷是誰給我發(fā)的消息,并且不知道該把消息回復(fù)到什么地方,因?yàn)槲覀冎g沒有建立連接通道

        back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)# 同樣也是阻塞狀態(tài),等待接收消息
        print('來自[%s:%s]的一條消息:33[1;44m%s33[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))

udp_client_socket.close()

client端

View Code

接下來,給大家說一個(gè)真實(shí)的例子,也就是實(shí)際當(dāng)中應(yīng)用的,那么這是個(gè)什么例子呢?就是我們電腦系統(tǒng)上的時(shí)間,windows系統(tǒng)的時(shí)間是和微軟的時(shí)間服務(wù)器上的時(shí)間同步的,而mac本是和蘋果服務(wù)商的時(shí)間服務(wù)器同步的,這是怎么做的呢,首先他們的時(shí)間服務(wù)器上的時(shí)間是和國(guó)家同步的,你們用我的系統(tǒng),那么你們的時(shí)間只要和我時(shí)間服務(wù)器上的時(shí)間同步就行了,對(duì)吧,我時(shí)間服務(wù)器是不是提供服務(wù)的啊,相當(dāng)于一個(gè)服務(wù)端,我們的電腦就相當(dāng)于客戶端,就是通過UDP來搞的。

我們自制一個(gè)時(shí)間服務(wù)器的代碼示例:

from socket import *
from time import strftime
import time
ip_port = ('127.0.0.1', 9000)
bufsize = 1024

tcp_server = socket(AF_INET, SOCK_DGRAM)
tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
tcp_server.bind(ip_port)

while True:
    msg, addr = tcp_server.recvfrom(bufsize)
    print('===>', msg)
    stru_time = time.localtime()  #當(dāng)前的結(jié)構(gòu)化時(shí)間
    if not msg:
        time_fmt = '%Y-%m-%d %X'
    else:
        time_fmt = msg.decode('utf-8')
    back_msg = strftime(time_fmt,stru_time)
    print(back_msg,type(back_msg))
    tcp_server.sendto(back_msg.encode('utf-8'), addr)

tcp_server.close()

server端

View Code

from socket import *
ip_port=('127.0.0.1',9000)
bufsize=1024

tcp_client=socket(AF_INET,SOCK_DGRAM)

while True:
    msg=input('請(qǐng)輸入時(shí)間格式(例%Y %m %d)>>: ').strip()
    tcp_client.sendto(msg.encode('utf-8'),ip_port)

    data=tcp_client.recv(bufsize)
    print('當(dāng)前日期:',str(data,encoding='utf-8'))

client端

View Code

UDP來個(gè)小練習(xí)吧:

練習(xí)的需求是這樣的:1、服務(wù)端需要提供的服務(wù)有:接收消息(時(shí)間格式的字符串)、將我的本地的時(shí)間轉(zhuǎn)換成接收到的消息的格式(也就是個(gè)時(shí)間格式的字符串)、發(fā)回給客戶端。2、客戶端自行想一下怎么寫。

TCP協(xié)議和UDP協(xié)議下socket的基本使用ok了,那我們來深入分析一下socket。(這一塊的內(nèi)容初學(xué)者不要看,對(duì)socket有些了解的同學(xué)可以研究一下,切記看不懂很正常,不要深究,現(xiàn)階段你們就是學(xué)習(xí)應(yīng)用為主!)>>>>看這里>>>>socket原理剖析,里面包含socket中各個(gè)方法的作用和方法中的參數(shù)。

這里我列出兩個(gè)簡(jiǎn)易描述socket各個(gè)參數(shù)和方法的圖,共大家參考:

socket類型:

  socket各個(gè)方法的解釋:

  

筆記

總結(jié)

以上是生活随笔為你收集整理的27 网络通信协议 udp tcp的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。