亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 3854|回復(fù): 0
收起左側(cè)

單片機(jī)串口通信原理實(shí)現(xiàn)的上下位機(jī)設(shè)計(jì)

[復(fù)制鏈接]
ID:698492 發(fā)表于 2020-2-26 13:38 | 顯示全部樓層 |閱讀模式
本文轉(zhuǎn)自:Flywithliye

1.  通信簡(jiǎn)介
通信有并行通信和串行通信兩種方式。在多微機(jī)系統(tǒng)以及現(xiàn)代測(cè)控系統(tǒng)中信息的交換多采用串行通信方式。
1)  并行通信
并行通信是指所傳送的數(shù)據(jù)各位同時(shí)進(jìn)行傳送。其優(yōu)點(diǎn)是傳送速度快,缺點(diǎn)是傳輸線多,通信線路費(fèi)用較高,并行傳送適用于近距離、傳送速度高的場(chǎng)合。
2)  串行通信
串行通信時(shí),傳送數(shù)據(jù)的各位按分時(shí)順序一位一位地傳送(例如先低位、后高位)。其優(yōu)點(diǎn)是傳輸線少,傳送通道費(fèi)用低,故適合長(zhǎng)距離數(shù)據(jù)傳送。缺點(diǎn)是傳送速度較低。
圖 1
2.  串行通信1)  串行通訊數(shù)據(jù)傳送方向a)  單工方式
通信雙方只有一條單向傳輸線,只允許數(shù)據(jù)由一方發(fā)送,另一方接收。
b)  半雙工方式
通信雙方只有一條雙向傳輸線,允許數(shù)據(jù)雙向傳送,但每時(shí)刻上只能有一方發(fā)送,另一方接收,這是一種能夠切換傳送方向的單工方式。
c)  全雙工方式
通信雙方只有兩條傳輸線,允許數(shù)據(jù)同時(shí)雙向傳送,其通信設(shè)備應(yīng)具有完全獨(dú)立的收發(fā)功能。
圖 2
2)  串行通信基本方式
為了準(zhǔn)確地發(fā)送、接收信息,發(fā)送者和接受者雙方必須協(xié)調(diào)工作。這種協(xié)調(diào)方法,從原理上可分成兩種:同步串行I/O和異步串行I/O。
a)  同步通信方式
在同步通信中,在數(shù)據(jù)或字符開始傳送前用同步字符(SYNC)來指示(常約定l一2個(gè)),由時(shí)鐘來實(shí)現(xiàn)發(fā)送端和接收端同步,當(dāng)檢測(cè)到規(guī)定的同步字符后,接下來就連續(xù)按順序傳送數(shù)據(jù)。同步字符是一特定的二進(jìn)制序列,在傳送的數(shù)據(jù)中不會(huì)出現(xiàn)。
同步通信方式由于不采用起始和停止位,是在同步字符后可以接較大的數(shù)據(jù)區(qū),同步字符所占部分很小,因此有較高的傳送效率。
發(fā)送、接收雙方都由統(tǒng)一的時(shí)鐘來發(fā)送、接收數(shù)據(jù)。也就是說,不光有數(shù)據(jù)傳輸線,還要附加同步時(shí)鐘線。這種方式,硬件較復(fù)雜、成本較高、傳送速率高。
b)  異步通信方式
異步通信方式時(shí),數(shù)據(jù)一幀一幀地傳送,不需要同步時(shí)鐘,實(shí)現(xiàn)簡(jiǎn)單。
在異步方式中,為了避免連續(xù)傳送過程中的誤差積累,每個(gè)字符都要獨(dú)立確定起始和結(jié)束(即每個(gè)字符都要重新同步),字符和字符間還可能有長(zhǎng)度不定的空閑時(shí)間。
3)  異步串行通信數(shù)據(jù)格式
一個(gè)字符在異步傳送中稱為一幀數(shù)據(jù)。一幀數(shù)據(jù)由4部分組成:起始位、數(shù)據(jù)位、奇偶位、停止位。
圖 3
上圖所示為不包含奇偶檢驗(yàn)位的一個(gè)數(shù)據(jù)幀。奇偶檢驗(yàn)位應(yīng)位于數(shù)據(jù)位后,停止位前。
a)  起始位
在沒有數(shù)據(jù)傳輸時(shí),通信線上處于邏輯“1”狀態(tài)。當(dāng)發(fā)送端要發(fā)送1個(gè)字符數(shù)據(jù)時(shí),首先發(fā)送1個(gè)邏輯“0”,這個(gè)低電平便是幀格式的起始位。其作用是向接收端表示發(fā)送端開始發(fā)送一幀數(shù)據(jù)了。接收端檢測(cè)到這個(gè)低電平后,就準(zhǔn)備接收數(shù)據(jù)。
b)  數(shù)據(jù)位
在起始位之后,發(fā)送端發(fā)出(或接收端接收)的是數(shù)據(jù)位,數(shù)據(jù)的位數(shù)沒有嚴(yán)格的限制,5~8 位均可。由低位到高位逐位發(fā)送。
c)  奇偶校驗(yàn)位
數(shù)據(jù)位發(fā)送完(接收完)之后,可發(fā)送一位用來驗(yàn)證數(shù)據(jù)在傳送過程中是否出錯(cuò)的奇偶校驗(yàn)位。奇偶校驗(yàn)是收發(fā)雙發(fā)預(yù)先約定的有限差錯(cuò)校驗(yàn)方法之一。有時(shí)也可不用奇偶校驗(yàn)。
d)  停止位
字符幀格式的最后部分是停止位,邏輯“高(1)”電平有效,它可占 1/2 位、1 位或 2 位。停止位表示傳送一幀信息的結(jié)束,也為發(fā)送下一幀數(shù)據(jù)做好了準(zhǔn)備。
4)  串行接口標(biāo)準(zhǔn)a)  RS-232
RS-232是美國(guó)電子工業(yè)協(xié)會(huì)EIA(Electronic Industry Association)制定的一種串行物理接口標(biāo)準(zhǔn)。RS是英文“推薦標(biāo)準(zhǔn)”的縮寫,232為標(biāo)識(shí)號(hào)。RS-232是對(duì)電氣特性以及物理特性的規(guī)定,只作用于數(shù)據(jù)的傳輸通路上,它并不內(nèi)含對(duì)數(shù)據(jù)的處理方式。RS-232標(biāo)準(zhǔn)是邏輯1為-3V~-15V,邏輯0為+3~+15V。
b)  RS-422
RS-422的電氣性能與RS-485完全一樣。主要的區(qū)別在于:RS-422 有4 根信號(hào)線:兩根發(fā)送、兩根接收。由于RS-422 的收與發(fā)是分開的所以可以同時(shí)收和發(fā)(全雙工),也正因?yàn)槿p工要求收發(fā)要有單獨(dú)的信道,所以RS-422適用于兩個(gè)站之間通信,星型網(wǎng)、環(huán)網(wǎng),不可用于總線網(wǎng);RS-485 只有2 根信號(hào)線,所以只能工作在半雙工模式,常用于總線網(wǎng)。
c)  RS-485
RS-232接口可以實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)的通信方式,但這種方式不能實(shí)現(xiàn)聯(lián)網(wǎng)功能。于是,為了解決這個(gè)問題,一個(gè)新的標(biāo)準(zhǔn)RS-485產(chǎn)生了。RS-485的數(shù)據(jù)信號(hào)采用差分傳輸方式,也稱作平衡傳輸,它使用一對(duì)雙絞線,將其中一線定義為A,另一線定義為B。通常情況下,發(fā)送驅(qū)動(dòng)器A、B之間的正電平在+2~+6V,是一個(gè)邏輯狀態(tài),負(fù)電平在-2~-6V,是另一個(gè)邏輯狀態(tài)。另有一個(gè)信號(hào)地C,在RS-485中還有一“使能”端,而在RS-422中這是可用可不用的。
3.  通信實(shí)驗(yàn)1)  實(shí)驗(yàn)環(huán)境的搭建
為實(shí)現(xiàn)在無附加硬件的條件下,使用PC機(jī)完成串行口通信實(shí)驗(yàn)。通過軟件對(duì)實(shí)驗(yàn)環(huán)境配置如下:
a)  虛擬串口的創(chuàng)建
使用Configure Virtual Serial Port Driver軟件在PC上創(chuàng)建一對(duì)虛擬串口(COM1和COM2),如圖所示。
圖 4
COM1和COM2為已連接的一對(duì)串口,分別為兩臺(tái)設(shè)備的接口(已虛擬連接)。設(shè)備A,B分別連接至COM1和COM2,即可收發(fā)數(shù)據(jù)。
b)  設(shè)備B的創(chuàng)建
此次實(shí)驗(yàn)中,設(shè)備B為單片微機(jī)(MCU)。其選型為AT89C52型,具備硬件UART功能。設(shè)備B電路實(shí)現(xiàn)由Protues軟件進(jìn)行模擬仿真。電路原理圖如圖所示。
圖 5
由于RS-232標(biāo)準(zhǔn)采用負(fù)邏輯,即邏輯1為-3V~-15V,邏輯0為+3~+15V。而本單片機(jī)系統(tǒng)為TTL信號(hào)系統(tǒng)。TTL電平規(guī)定,+5V等價(jià)于邏輯“1”,0V等價(jià)于邏輯“0”。因此,DB-9與單片機(jī)的連接需要進(jìn)行電平轉(zhuǎn)換,如上圖所示,選用了MAX232芯片。
圖 6
如圖所示,P1組件(COMPIM)即為DB-9接口,使用MAX232芯片進(jìn)行電平轉(zhuǎn)換后與AT89C52串行口P3.0/RXD,P3.1/TXD分別相連接。(由于軟件特殊原因,在MAX232芯片1通道R1OUT及T1OUT處增加74LS04非門進(jìn)行處理,實(shí)際中無需取反處理。)
圖中組件RECEIVE和SEND為Protues軟件提供的VIRTUAL TERMINAL(虛擬終端)可用于觀察AT89C52接收和發(fā)送到的數(shù)據(jù)。僅用于調(diào)試觀察。
2)  實(shí)驗(yàn)內(nèi)容說明
本次實(shí)驗(yàn)涉及兩個(gè)設(shè)備,設(shè)備B為上述單片微機(jī),用以模擬一個(gè)外部設(shè)備。設(shè)備A為PC機(jī)本身。
設(shè)備A,B分別都運(yùn)行有簡(jiǎn)單的程序。設(shè)備A的程序存儲(chǔ)器中加載有簡(jiǎn)單回傳程序,負(fù)責(zé)將接收到的字符/字符串(以回車換行結(jié)尾)保持原接收狀態(tài)并向外發(fā)送。設(shè)備B即PC,其上運(yùn)行有窗口程序,負(fù)責(zé)向設(shè)備A發(fā)送字符/字符串,并接收顯示其回傳的數(shù)據(jù)。
實(shí)驗(yàn)時(shí)設(shè)備A連接COM1口,設(shè)備B連接COM2口。由PC窗口程序輸入測(cè)試數(shù)據(jù)后發(fā)送至單片微機(jī)后,由后者保持原樣回傳并顯示在PC窗口程序接收窗口。
3)  單片機(jī)程序的編制
由于該芯片自帶硬件UART功能且由于實(shí)驗(yàn)環(huán)境所限,此次實(shí)驗(yàn)中,發(fā)送接收通過配置相關(guān)寄存器控制硬件模塊實(shí)現(xiàn),未采用軟件定時(shí)器模擬通信時(shí)序的方式。
程序主要包括以下三個(gè)部分:主函數(shù),串行口配置函數(shù),發(fā)送函數(shù)及串行口中斷服務(wù)函數(shù)。
a)  程序變量定義及函數(shù)聲明
b)  程序主函數(shù)
c)  其他子函數(shù)
其他在主函數(shù)中調(diào)用的具體子函數(shù)實(shí)現(xiàn)由附件1列出。
4)  窗口應(yīng)用程序的編制
本次實(shí)驗(yàn)的窗口程序使用VB.NET語言在VS2010環(huán)境下編寫。
程序中主要由.NET提供的SerialPort控件實(shí)現(xiàn),輔之以必要的其他窗口控件。窗口布局如圖所示:
圖 7
a)  參數(shù)設(shè)置函數(shù)
b)  數(shù)據(jù)接收函數(shù)
SerialPort的事件DataReceived調(diào)用Sp_Receiving實(shí)現(xiàn)數(shù)據(jù)接收。當(dāng)輸入緩沖區(qū)接收到1個(gè)字符后驅(qū)動(dòng)該事件發(fā)生,并調(diào)用Sp_Receiving函數(shù)準(zhǔn)備開始接收數(shù)據(jù)。當(dāng)讀取到緩沖區(qū)中的回車換行符后,將接受到的數(shù)據(jù)顯示在TextBox控件中。若在超時(shí)以后仍未讀取到回車換行符,則執(zhí)行空操作后退出接受程序,退出前清空接收緩沖區(qū)。既本窗口程序僅接受并顯示以回車換行結(jié)尾的數(shù)據(jù)包。
c)  數(shù)據(jù)發(fā)送函數(shù)
數(shù)據(jù)發(fā)送過程由按鍵按下事件驅(qū)動(dòng)調(diào)用。判斷是否發(fā)送新行(本次實(shí)驗(yàn)中必須勾選)后是否為對(duì)話模式后,發(fā)送數(shù)據(jù)。
d)  其他子函數(shù)
其他子函數(shù)包括PC可用串口讀取,串口打開,串口關(guān)閉,及相關(guān)事件處理函數(shù)。其具體實(shí)現(xiàn)由附件2給出。
5)  實(shí)驗(yàn)過程a)  串口有關(guān)參數(shù)設(shè)置
表 1
串口參數(shù)約定

設(shè)備A(PC)
設(shè)備B(MCU)
COM編號(hào)
COM1
COM2
波特率(bps)
9600
數(shù)據(jù)位
8
校驗(yàn)位
停止位
1
按照表1設(shè)置串口參數(shù)如下。
圖 8
圖 9

左圖為窗口程序設(shè)置,右圖為仿真軟件中對(duì)與MCU接口的DB-9接頭的屬性設(shè)置。MCU中的配置由配置相關(guān)寄存器完成,如下所示。
b)  啟動(dòng)MCU仿真
點(diǎn)擊下圖第一個(gè)按鈕啟動(dòng)仿真。
圖 10
出現(xiàn)如下圖所示內(nèi)容說明仿真成功執(zhí)行。
圖 11
c)  打開上位機(jī)串口
點(diǎn)擊打開串口按鍵,若在串口狀態(tài)處顯示已打開,則說明上位機(jī)以成功打開串口。
圖 12
d)  輸入信息并發(fā)送
在發(fā)送輸入下的文本框中輸入任意字符串(長(zhǎng)度不可超出單片機(jī)接收緩沖區(qū)長(zhǎng)度-2)后,點(diǎn)擊右側(cè)發(fā)送按鈕。此處發(fā)送“This is a test!”。
圖 13
e)  單片機(jī)回傳數(shù)據(jù)
上位機(jī)發(fā)送數(shù)據(jù)“This is a test!”之后,單片機(jī)回傳“MCU received: This is a test!”并顯示在接收顯示窗口中,如下圖所示。
圖 14
f)  單片機(jī)接收/發(fā)送
在步驟e)執(zhí)行之前,單片機(jī)接收到的內(nèi)容和發(fā)送的內(nèi)容如下圖所示。
圖 15
圖 16


2、  TCP通信1.  Socket套接字1)  簡(jiǎn)介
網(wǎng)絡(luò)上的兩個(gè)程序通過一個(gè)雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個(gè)連接的一端稱為一個(gè)socket。
套接字(socket)是通信的基石,是支持TCP/IP協(xié)議的網(wǎng)絡(luò)通信的基本操作單元。它是網(wǎng)絡(luò)通信過程中端點(diǎn)的抽象表示,包含進(jìn)行網(wǎng)絡(luò)通信必須的五種信息:連接使用的協(xié)議,本地主機(jī)的IP地址,本地進(jìn)程的協(xié)議端口,遠(yuǎn)地主機(jī)的IP地址,遠(yuǎn)地進(jìn)程的協(xié)議端口。
Socket是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層,它是一組接口。在設(shè)計(jì)模式中,Socket其實(shí)就是一個(gè)門面模式,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面,對(duì)用戶來說,一組簡(jiǎn)單的接口就是全部,讓Socket去組織數(shù)據(jù),以符合指定的協(xié)議。
2)  分類
TCP/IP的socket提供下列三種類型套接字。
a)  流式套接字(SOCK_STREAM)
提供了一個(gè)面向連接(TCP)、可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無差錯(cuò)、無重復(fù)地發(fā)送,且按發(fā)送順序接收。內(nèi)設(shè)流量控制,避免數(shù)據(jù)流超限;數(shù)據(jù)被看作是字節(jié)流,無長(zhǎng)度限制。文件傳送協(xié)議(FTP)即使用流式套接字。
b)  數(shù)據(jù)報(bào)式套接字(SOCK_DGRAM)
提供了一個(gè)無連接服務(wù)(UDP)。數(shù)據(jù)包以獨(dú)立包形式被發(fā)送,不提供無錯(cuò)保證,數(shù)據(jù)可能丟失或重復(fù),并且接收順序混亂。網(wǎng)絡(luò)文件系統(tǒng)(NFS)使用數(shù)據(jù)報(bào)式套接字。
c)  原始式套接字(SOCK_RAW)
該接口允許對(duì)較低層協(xié)議,如IP、ICMP直接訪問。常用于檢驗(yàn)新的協(xié)議實(shí)現(xiàn)或訪問現(xiàn)有服務(wù)中配置的新設(shè)備。
2.  TCP簡(jiǎn)介
TCP(Transmission Control Protocol 傳輸控制協(xié)議)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。利用TCP協(xié)議進(jìn)行通信時(shí),首先要建立通信雙方的連接。一旦連接建立完成,就可以進(jìn)行通信。TCP提供了數(shù)據(jù)確認(rèn)和數(shù)據(jù)重傳機(jī)制,保證了發(fā)送的數(shù)據(jù)一定能到達(dá)通信的對(duì)方。
3.  TCP通信過程
TCP通信過程如下圖所示。
圖 17
服務(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é)束。
4.  TCP服務(wù)器程序流程1)  建立連接階段
  • 調(diào)用socket(),分配文件描述符,即監(jiān)聽套接字。
  • 調(diào)用bind(),將套接字與本地IP地址和端口綁定。
  • 調(diào)用listen(),監(jiān)聽特定端口,socket()創(chuàng)建的套接字是主動(dòng)的,調(diào)用listen使得該文件描述符為監(jiān)聽套接字,變主動(dòng)為被動(dòng)。
  • 調(diào)用accept(),阻塞等待客戶端連接。
2)  數(shù)據(jù)交互階段
  • 調(diào)用read(),阻塞等待客戶端發(fā)送請(qǐng)求,收到請(qǐng)求后從read()返回,處理客戶端請(qǐng)求。
  • 調(diào)用write(),將處理結(jié)果發(fā)送給客戶端,然后繼續(xù)調(diào)用read()等待客戶端請(qǐng)求。
3)  關(guān)閉連接
  • 當(dāng)read()返回0的時(shí)候,說明客戶端發(fā)來了FIN數(shù)據(jù)包,即關(guān)閉連接,也會(huì)調(diào)用close()關(guān)閉連接套接字和監(jiān)聽套接字。
5.  TCP客戶端程序流程1)  建立連接階段
  • 調(diào)用socket(),分配文件描述符。
  • 調(diào)用connect(),向服務(wù)器發(fā)送建立連接請(qǐng)求。
2)  數(shù)據(jù)交互階段
  • 調(diào)用write(),將請(qǐng)求發(fā)送給服務(wù)器。
  • 調(diào)用read(),阻塞等待服務(wù)器應(yīng)答。
3)  關(guān)閉連接
  • 當(dāng)沒有數(shù)據(jù)發(fā)送的時(shí)候,調(diào)用close()關(guān)閉連接套接字,即關(guān)閉連接,向服務(wù)器發(fā)送FIN數(shù)據(jù)報(bào)。
6.  通信實(shí)驗(yàn)1)  實(shí)驗(yàn)環(huán)境的搭建
在編寫實(shí)驗(yàn)程序前,須在編譯器中添加庫文件ws2_32.lib。可通過編譯器軟件設(shè)置實(shí)現(xiàn),也可通過包含如下代碼實(shí)現(xiàn):#pragma comment(lib,"ws2_32.lib")
2)  實(shí)驗(yàn)內(nèi)容說明
本次實(shí)驗(yàn)包括服務(wù)器端程序和客戶端程序,由C語言編寫的控制臺(tái)程序?qū)崿F(xiàn)。程序順序執(zhí)行。實(shí)驗(yàn)實(shí)現(xiàn)客戶端程序和服務(wù)器端程序的通信(字符串)。
3)  服務(wù)器端程序的編制a)  程序變量定義及函數(shù)聲明
b)  程序主函數(shù)
c)  其他子函數(shù)
其他子函數(shù)包括用于初始化套接字,創(chuàng)建套接字,綁定IP和端口,設(shè)置監(jiān)聽狀態(tài),等待客戶端發(fā)起連接的程序,其中分別調(diào)用了Socket中提供的功能函數(shù),但是加入了一些簡(jiǎn)單的顯示和錯(cuò)誤處理。其具體實(shí)現(xiàn)由附件3給出。
4)  客戶端程序的編制a)  程序變量定義及函數(shù)聲明
b)  程序主函數(shù)
c)  其他子函數(shù)
其他子函數(shù)包含用于初始化套接字,創(chuàng)建套接字,連接服務(wù)器及釋放套接字的函數(shù)。為了適應(yīng)在本地實(shí)驗(yàn)和同網(wǎng)段實(shí)驗(yàn)的需求,連接服務(wù)器的子函數(shù)Connect_Socket()中從鍵盤獲取輸入的IP地址和端口實(shí)現(xiàn)連接。其具體實(shí)現(xiàn)由附件4給出。
5)  實(shí)驗(yàn)過程a)  啟動(dòng)服務(wù)器端程序并等待連接b)  啟動(dòng)客戶端程序并發(fā)起連接
輸入服務(wù)器IP地址和端口后即可發(fā)起連接。
c)  客戶端發(fā)送消息
輸入消息并回車即可發(fā)送。
圖 18
圖 19
d)  服務(wù)器端發(fā)送消息
輸入消息并回車即可發(fā)送。
注意:由于程序順序/循環(huán)執(zhí)行,非事件驅(qū)動(dòng)結(jié)構(gòu),因此必須在接收到對(duì)方發(fā)送的數(shù)據(jù)后,己方方可發(fā)送。
3、  UDP通信1.  UDP簡(jiǎn)介
UDP是無連接的不可靠的傳輸協(xié)議。采用UDP進(jìn)行通信時(shí),不需要建立連接,可以直接向一個(gè)IP地址發(fā)送數(shù)據(jù),但是不能保證對(duì)方能收到。
對(duì)于基于UDP面向無連接的套接字編程來說,服務(wù)器端和客戶端這種概念不是特別的嚴(yán)格。可以把服務(wù)器端稱為接收端,客戶端就是發(fā)送數(shù)據(jù)的發(fā)送端。
2.  UDP通信過程
圖 20
服務(wù)器端先初始化Socket,然后與端口綁定(bind),在這時(shí)如果有個(gè)客戶端初始化一個(gè)Socket,客戶端發(fā)送數(shù)據(jù)請(qǐng)求,服務(wù)器端接收請(qǐng)求并處理請(qǐng)求,然后把回應(yīng)數(shù)據(jù)發(fā)送給客戶端,客戶端讀取數(shù)據(jù),一次交互結(jié)束。
注意到,在進(jìn)行端口綁定(bind)之后,服務(wù)器端不需要對(duì)端口進(jìn)行監(jiān)聽(listen),也不需要調(diào)用等待連接(accept)阻塞,等待客戶端連接。而客戶端無需使用連接(connect)事先與服務(wù)器建立連接。
3.  UDP服務(wù)器程序流程
  • 建立套接字文件描述符,使用函數(shù)socket(),生成套接字文件描述符。
  • 設(shè)置服務(wù)器地址和偵聽端口,初始化要綁定的網(wǎng)絡(luò)地址結(jié)構(gòu)。
  • 綁定偵聽端口,使用bind()函數(shù),將套接字文件描述符和一個(gè)地址類型變量進(jìn)行綁定。
  • 接收客戶端的數(shù)據(jù),使用recvfrom()函數(shù)接收客戶端的網(wǎng)絡(luò)數(shù)據(jù)。
  • 向客戶端發(fā)送數(shù)據(jù),使用sendto()函數(shù)向服務(wù)器主機(jī)發(fā)送數(shù)據(jù)。
  • 關(guān)閉套接字,使用close()函數(shù)釋放資源。UDP協(xié)議的客戶端流程.
4.  UDP客戶端程序流程
  • 建立套接字文件描述符,socket()
  • 設(shè)置服務(wù)器地址和端口,struct sockaddr
  • 向服務(wù)器發(fā)送數(shù)據(jù),sendto()
  • 接收服務(wù)器的數(shù)據(jù),recvfrom()
  • 關(guān)閉套接字,close()
5.  通信實(shí)驗(yàn)1)  實(shí)驗(yàn)內(nèi)容說明
本次實(shí)驗(yàn)進(jìn)行了更為簡(jiǎn)單的驗(yàn)證次實(shí)驗(yàn)啟動(dòng)服務(wù)器后監(jiān)聽某端口后,由客戶端發(fā)送一固定數(shù)據(jù)給服務(wù)器,服務(wù)器接收并顯示后。雙方釋放套接字并結(jié)束程序。
2)  服務(wù)器端程序的編制a)  程序變量定義及函數(shù)聲明
b)  程序主函數(shù)
c)  其他子函數(shù)
其他子函數(shù)包括用于初始化套接字,綁定IP和端口的函數(shù),其中分別調(diào)用了Socket中提供的功能函數(shù)。其具體實(shí)現(xiàn)由附件5給出。
3)  客戶端程序的編制a)  程序變量定義及函數(shù)聲明
b)  程序主函數(shù)
c)  其他子函數(shù)
其他子函數(shù)包括用于初始化套接字,設(shè)置服務(wù)器IP和端口的函數(shù),其中分別調(diào)用了Socket中提供的功能函數(shù)。其具體實(shí)現(xiàn)由附件6給出。
4)  實(shí)驗(yàn)過程a)  啟動(dòng)服務(wù)器并監(jiān)聽端口b)  啟動(dòng)客戶端向服務(wù)器發(fā)送c)  服務(wù)器接收并顯示
圖 21
圖 22

5.  附件五(UDP Server程序)
  #include<stdio.h>  
  #include<winsock.h>                           /*引入winsock頭文件*/  
  #pragma comment(lib,"ws2_32.lib")  
   
  char Receivebuf[100];       /*接受數(shù)據(jù)的緩沖區(qū)*/  
  int length;  
   
  SOCKET socket_send;         /*定義套接字*/  
  SOCKADDR_IN Server_add;     /*服務(wù)器地址信息結(jié)構(gòu)*/  
SOCKADDR_IN Client_add;     /*客戶端地址信息結(jié)構(gòu)*/  
WORD wVersionRequested;     /*字(word):unsigned short*/  
WSADATA wsaData;            /*庫版本信息結(jié)構(gòu)*/  
int error;                  /*表示錯(cuò)誤*/  
  
void Init_Socket();         /*初始化套接字*/  
void Bind_Socket();         /*綁定套接字*/  
  
int main()  
{  
    memset(Receivebuf,0,100);                  /*清空接收緩沖*/  
    Init_Socket();                             /*初始化套接字*/  
  
    socket_send=socket(AF_INET,SOCK_DGRAM,0);  /*創(chuàng)建套接字*/  
    Bind_Socket();                             /*綁定套接字*/  
      
    recvfrom(socket_send,Receivebuf,100,0,(SOCKADDR*)&Client_add,&length);  
    printf("客戶端:%s\n",Receivebuf);         /*接收并顯示數(shù)據(jù)*/  
  
    closesocket(socket_send);                  /*釋放套接字資源*/  
    WSACleanup();                              /*關(guān)閉動(dòng)態(tài)鏈接庫*/  
    system("pause");  
    return 0;  
}  
  
void Init_Socket()  
{  
    /*-------------------------初始化套接字庫---------------------------*/  
    /*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/  
    wVersionRequested = MAKEWORD( 2, 2 );     
    /*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/  
    error = WSAStartup( wVersionRequested, &wsaData);     
    if(error!=0)  
    {  
        printf("加載套接字失敗!\n");  
        return 0;                              /*程序結(jié)束*/  
    }  
    /*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/  
    if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)   
    {     
        WSACleanup( );                         /*不符合,關(guān)閉套接字庫*/  
        return 0;                              /*程序結(jié)束*/  
    }  
    printf("加載套接字成功。\n");  
}  
  
void Bind_Socket()  
{  
    /*----------------------設(shè)置服務(wù)器地址-----------------------*/  
    Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/  
    Server_add.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  
    Server_add.sin_port=htons(5000);/*端口號(hào)*/  
  
    /*綁定套接字*/  
    bind(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR));  
    length=sizeof(SOCKADDR);  
    printf("綁定成功。\n正在監(jiān)聽\n");  
}  

6.  附件六(UDP Client程序)
  #include<stdio.h>  
  #include<winsock.h>               /*引入winsock頭文件*/  
  #pragma comment(lib,"ws2_32.lib")  
   
  #define Msg "This is a test!"   /*待發(fā)送數(shù)據(jù)*/  
  SOCKET socket_client;           /*定義套接字*/  
  SOCKADDR_IN Server_add;         /*服務(wù)器地址信息結(jié)構(gòu)*/  
  WORD wVersionRequested;         /*字(word):unsigned short*/  
  WSADATA wsaData;                /*庫版本信息結(jié)構(gòu)*/  
int error;                      /*表示錯(cuò)誤*/  
  
void Init_Socket();             /*初始化套接字*/  
void Set_Server();              /*設(shè)置服務(wù)器地址和端口*/  
int main()  
{  
    Init_Socket();                                 /*初始化套接字*/                                       
    socket_client=socket(AF_INET,SOCK_DGRAM,0);    /*創(chuàng)建套接字*/  
    Set_Server();                                  /*設(shè)置服務(wù)器地址和端口*/  
    /*發(fā)送數(shù)據(jù)*/  
    sendto(socket_client,Msg,strlen(Msg)+1,0,(SOCKADDR*)&Server_add,sizeof(SOCKADDR));  
    printf("已發(fā)送數(shù)據(jù)至服務(wù)器\n");  
    closesocket(socket_client);                    /*釋放套接字資源*/  
    WSACleanup();                                  /*關(guān)閉動(dòng)態(tài)鏈接庫*/  
    system("pause");  
    return 0;  
}  
  
void Init_Socket()  
{  
    /*-------------------------初始化套接字庫---------------------------*/  
    /*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/  
    wVersionRequested = MAKEWORD( 2, 2 );     
    /*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/  
    error = WSAStartup( wVersionRequested, &wsaData);     
    if(error!=0)  
    {  
        printf("加載套接字失敗!\n");  
        return 0;                                  /*程序結(jié)束*/  
    }  
    /*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/  
    if ( LOBYTE( wsaData.wVersion ) != 2 ||  
           HIBYTE( wsaData.wVersion ) != 2 )   
    {     
        WSACleanup( );                             /*不符合,關(guān)閉套接字庫*/  
        return 0;                                  /*程序結(jié)束*/  
    }  
    printf("加載套接字成功。\n");  
}  
  
void Set_Server()  
{  
    /*----------------------設(shè)置服務(wù)器地址-----------------------*/  
    Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/  
    Server_add.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  
    Server_add.sin_port=htons(5000);               /*端口號(hào)*/  
    printf("服務(wù)器設(shè)置成功。\n");  
}  


4.  附件四(TCP Client程序)
  #include<stdio.h>  
  #include<winsock.h>       /*引入winsock頭文件*/  
  #pragma comment(lib,"ws2_32.lib")  
   
  char Sendbuf[100];      /*發(fā)送數(shù)據(jù)的緩沖區(qū)*/  
  char Receivebuf[100];   /*接受數(shù)據(jù)的緩沖區(qū)*/  
  int SendLen;            /*發(fā)送數(shù)據(jù)的長(zhǎng)度*/  
  int ReceiveLen;         /*接收數(shù)據(jù)的長(zhǎng)度*/  
  char IPaddress[16];     /*IP地址數(shù)組*/  
char Port[6];           /*端口數(shù)組*/  
  
SOCKET socket_send;     /*定義套接字*/  
SOCKADDR_IN Server_add; /*服務(wù)器地址信息結(jié)構(gòu)*/  
WORD wVersionRequested; /*字(word):unsigned short*/  
WSADATA wsaData;        /*庫版本信息結(jié)構(gòu)*/  
int error;              /*表示錯(cuò)誤*/  
  
int Init_Socket();      /*初始化套接字*/  
void Create_Socket();   /*創(chuàng)建套接字*/  
void Connect_Socket();  /*連接服務(wù)器*/  
void Close_Socket();    /*釋放套接字*/  
  
int main()  
{  
    Init_Socket();                                      /*初始化套接字*/  
    Create_Socket();                                    /*創(chuàng)建套接字*/  
    Connect_Socket();                                   /*連接服務(wù)器*/  
  
    while(1)                                            /*具體通信過程*/  
    {     
        /*---------------發(fā)送數(shù)據(jù)過程----------*/  
        printf("請(qǐng)輸入消息:");  
        gets(Sendbuf);                                  //獲取輸入的數(shù)據(jù)  
        SendLen = send(socket_send,Sendbuf,100,0);      //啟動(dòng)發(fā)送  
        if(SendLen < 0)  
        {  
            printf("發(fā)送失敗!\n");                      //發(fā)送失敗  
            break;  
        }  
  
        /*--------------接收數(shù)據(jù)過程---------------*/  
        ReceiveLen =recv(socket_send,Receivebuf,100,0); //結(jié)束數(shù)據(jù)存緩沖區(qū)  
        if(ReceiveLen<0)  
        {  
            printf("連接關(guān)閉或接收失敗\n程序退出\n");   //接收或連接失敗  
            break;  
        }  
        else                                             
        {  
            printf("來自服務(wù)器:%s\n",Receivebuf);      //顯示收到的數(shù)據(jù)  
        }     
    }  
    Close_Socket();                                     /*釋放套接字*/  
    return 0;  
}  
  
int Init_Socket()  
{  
    /*------------初始化套接字庫---------------*/  
    /*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/  
    wVersionRequested = MAKEWORD( 2, 2 );     
    /*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/  
    error = WSAStartup( wVersionRequested, &wsaData);     
    if(error!=0)  
    {  
        printf("加載套接字失敗。\n");  
        return 0;                                       /*程序結(jié)束*/  
    }  
    else  
    {  
        printf("加載套接字成功。\n");  
    }  
    /*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/  
    if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)   
    {     
        WSACleanup( );                                  /*不符合,關(guān)閉套接字庫*/  
        return 0;                                       /*程序結(jié)束*/  
    }  
    else  
    {  
        printf("加載版本號(hào)符合。\n");  
    }  
}  
  
void Create_Socket()  
{  
    /*-------------進(jìn)行連接服務(wù)器--------------*/  
    /*客戶端創(chuàng)建套接字,但是不需要綁定的,只需要和服務(wù)器建立起連接就可以了。*/  
    /*socket_sendr表示的是套接字,Server_add服務(wù)器的地址結(jié)構(gòu)*/  
    socket_send=socket(AF_INET,SOCK_STREAM,0);  
}  
  
void Connect_Socket()  
{  
    /*------------設(shè)置服務(wù)器地址---------------*/  
    Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/  
    /*服務(wù)器的地址,將一個(gè)點(diǎn)分十進(jìn)制表示為IP地址,inet_ntoa是將地址轉(zhuǎn)成字符串*/  
    puts("輸入IP地址:");  
    gets(IPaddress);  
    puts("輸入端口:");  
    gets(Port);  
    Server_add.sin_addr.S_un.S_addr = inet_addr(IPaddress);  
    Server_add.sin_port=htons(atoi(Port));              /*端口號(hào)*/  
    /*-------------創(chuàng)建用于連接的套接字--------*/  
    /*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相關(guān)的協(xié)議。*/  
    if(connect(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR)) == SOCKET_ERROR)  
    {  
        printf("服務(wù)器連接失敗。\n");  
    }  
    else  
    {  
        printf("服務(wù)器連接成功。\n");  
    }  
}  
  
void Close_Socket()  
{  
    /*---------釋放套接字,關(guān)閉動(dòng)態(tài)庫----------*/  
    closesocket(socket_send);   /*釋放套接字資源*/  
    WSACleanup();               /*關(guān)閉動(dòng)態(tài)鏈接庫*/  
}  

3.  附件三(TCP Server程序)
      #include<stdio.h>  
  #include<winsock.h>       /*引入winsock頭文件*/  
  #pragma comment(lib,"ws2_32.lib")  
   
  #define IPaddress "127.0.0.1" /*IP地址*/  
  #define Port "5000"           /*端口*/  
   
  char Sendbuf[100];      /*發(fā)送數(shù)據(jù)的緩沖區(qū)*/  
  char Receivebuf[100];   /*接受數(shù)據(jù)的緩沖區(qū)*/  
int SendLen;            /*發(fā)送數(shù)據(jù)的長(zhǎng)度*/  
int ReceiveLen;         /*接收數(shù)據(jù)的長(zhǎng)度*/  
int Length;             /*表示SOCKADDR的大小*/  
  
SOCKET socket_server;   /*定義服務(wù)器套接字*/  
SOCKET socket_receive;  /*定義用于連接套接字*/  
SOCKADDR_IN Server_add; /*服務(wù)器地址信息結(jié)構(gòu)*/  
SOCKADDR_IN Client_add; /*客戶端地址信息結(jié)構(gòu)*/  
WORD wVersionRequested; /*字(word):unsigned short*/  
WSADATA wsaData;        /*庫版本信息結(jié)構(gòu)*/  
int error;              /*表示錯(cuò)誤*/  
  
int Init_Socket();      /*初始化套接字*/  
void Create_Socket();   /*創(chuàng)建套接字*/  
int Bind_Socket();      /*綁定IP和端口*/  
int Listen_Socket();    /*設(shè)置監(jiān)聽狀態(tài)*/  
int Wait_Socket();      /*等待客戶端連接*/  
void Close_Socket();    /*釋放套接字*/  
  
int main()  
{  
    Init_Socket();                                            /*初始化套接字*/  
    Create_Socket();                                          /*創(chuàng)建套接字*/  
    Bind_Socket();                                            /*綁定IP和端口*/  
    Listen_Socket();                                          /*設(shè)置監(jiān)聽狀態(tài)*/  
    Wait_Socket();                                            /*等待客戶端連接*/  
      
    while(1)            /*具體通信過程*/  
    {     
        /*--------接收數(shù)據(jù)---------*/  
        ReceiveLen =recv(socket_receive,Receivebuf,100,0);    //接收數(shù)據(jù)存緩沖區(qū)  
        if(ReceiveLen<0)                                      //連接或接收失敗  
        {  
            printf("客戶端中斷連接或接收失敗\n程序退出\n");  
            break;  
        }  
        else  
        {  
            printf("來自客戶端:%s\n",Receivebuf);            //顯示接收到的數(shù)據(jù)  
        }     
         
        /*--------發(fā)送數(shù)據(jù)---------*/  
        printf("請(qǐng)輸入消息:");  
        gets(Sendbuf);                                        //獲取輸入的數(shù)據(jù)  
        SendLen=send(socket_receive,Sendbuf,100,0);           //啟動(dòng)發(fā)送  
        if(SendLen<0)  
        {  
            printf("發(fā)送失敗。\n");                           //本次發(fā)送失敗  
            break;  
        }  
    }  
    Close_Socket();                                           /*釋放連接*/  
    return 0;  
}  
  
int Init_Socket()  
{  
    /*------------初始化套接字庫---------------*/  
    /*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/  
    wVersionRequested = MAKEWORD( 2, 2 );     
    /*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/  
    error = WSAStartup( wVersionRequested, &wsaData);     
    if(error!=0)  
    {  
        printf("加載套接字失敗。\n");  
        return 0;                                             /*程序結(jié)束*/  
    }  
    else  
    {  
        printf("加載套接字成功。\n");  
    }  
    /*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/  
    if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)   
    {     
        WSACleanup( );                                        /*不符合,關(guān)閉套接字庫*/  
        return 0;                                             /*程序結(jié)束*/  
    }  
    else  
    {  
        printf("加載版本號(hào)符合。\n");  
    }  
    return 1;  
}  
  
void Create_Socket()  
{  
    /*------------設(shè)置連接地址-----------------*/  
    Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/  
    Server_add.sin_addr.S_un.S_addr=inet_addr(IPaddress);     /*主機(jī)地址*/  
    Server_add.sin_port=htons(atoi(Port));/*端口號(hào)*/  
  
    /*------------創(chuàng)建套接字-------------------*/  
    /*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相關(guān)的協(xié)議。*/  
    socket_server=socket(AF_INET,SOCK_STREAM,0);  
}  
  
int Bind_Socket()  
{  
    /*---綁定套接字到本地的某個(gè)地址和端口上----*/  
    /*socket_server為套接字,(SOCKADDR*)&Server_add為服務(wù)器地址*/  
    if(bind(socket_server,(SOCKADDR*)&Server_add,sizeof(SOCKADDR) )==SOCKET_ERROR)  
    {  
        printf("綁定失敗。\n");  
        return 0;  
    }  
    else  
    {  
        printf("套接字綁定成功。\n");  
        printf("當(dāng)前主機(jī)地址:");  
        printf(IPaddress);  
        printf("\n當(dāng)前主機(jī)端口:");  
        printf(Port);  
        printf("\n");  
    }  
    return 1;  
}  
  
int Listen_Socket()  
{  
    /*------------設(shè)置套接字為監(jiān)聽狀態(tài)---------*/  
    /*監(jiān)聽狀態(tài),為連接做準(zhǔn)備,最大等待的數(shù)目為5*/  
    if(listen(socket_server,5)<0)  
    {  
        printf("監(jiān)聽失敗\n");  
        return 0;  
    }  
    else  
    {  
        printf("監(jiān)聽成功\n");  
        return 1;  
    }  
}  
  
int Wait_Socket()  
{  
    /*------------接受連接---------------------*/  
    Length=sizeof(SOCKADDR);  
    /*接受客戶端的發(fā)送請(qǐng)求,等待客戶端發(fā)送connect請(qǐng)求*/  
    socket_receive=accept(socket_server,(SOCKADDR*)&Client_add,&Length);  
    if(socket_receive==SOCKET_ERROR)  
    {  
        printf("客戶端連接失敗。");  
        return 0;  
    }  
    else  
    {  
        printf("客戶端連接成功。\n");  
        return 1;  
    }  
}  
  
void Close_Socket()  
{  
    /*---------釋放套接字,關(guān)閉動(dòng)態(tài)庫----------*/  
    closesocket(socket_receive);                              /*釋放客戶端的套接字資源*/  
    closesocket(socket_server);                               /*釋放套接字資源*/  
    WSACleanup();                                             /*關(guān)閉動(dòng)態(tài)鏈接庫*/  
}  

7.  附件七(單片機(jī)原理圖)




轉(zhuǎn)自 Flywithliye 相關(guān)資料下載:http://www.denmoz.com/bbs/dpj-180566-1.html

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表