已知字符串長度情況下完善回聲客戶端
# gcc echo_client2.c -o eclient2
# ./eclient2 127.0.0.1 9190
Connected
Input message (Q to quit): orange
Message from server: orange
Input message (Q to quit): hhhhhhhhhhhhhhhhhhhhhhhhhhhh
Message from server: hhhhhhhhhhhhhhhhhhhhhhhhhhhh
Input message (Q to quit): q
服務(wù)端同上一章春塌。
定義應(yīng)用層協(xié)議
原書中有些bug,服務(wù)端接收到的操作數(shù)個(gè)數(shù)沒有轉(zhuǎn)換成int寺旺。經(jīng)fix后代碼見附錄男窟,運(yùn)行結(jié)果如下:
# ./opserver 9190
Connected client 1
Connected client 2
Connected client 3
# ./opclient 127.0.0.1 9190
Connected
Input operand count: 3
Input operand: 1
Input operand: 5
Input operand: 9
Input operator: +
Operation result: 15
# ./opclient 127.0.0.1 9190
Connected
Input operand count: 4
Input operand: 16
Input operand: 8
Input operand: 4
Input operand: 2
Input operator: -
Operation result: 2
# ./opclient 127.0.0.1 9190
Connected
Input operand count: 2
Input operand: 5
Input operand: 7
Input operator: *
Operation result: 35
TCP原理
I/O緩沖特性:
- I/O緩沖在每個(gè)TCP套接字中單獨(dú)存在。
- I/O緩沖在創(chuàng)建套接字時(shí)自動(dòng)生成蒿囤。
- 即使關(guān)閉套接字也會(huì)繼續(xù)傳遞輸出緩沖區(qū)中的遺留數(shù)據(jù)客们。
- 關(guān)閉套接字將丟失輸入緩沖區(qū)中的遺留數(shù)據(jù)。
習(xí)題
- 請(qǐng)說明TCP套接字連接設(shè)置的三次握手過程材诽。尤其是3次數(shù)據(jù)交換過程每次收發(fā)的數(shù)據(jù)內(nèi)容底挫。
1)A向B發(fā)起連接,發(fā)送SYN包(SYN=1脸侥,seg=X)
2)B回復(fù)SYN_ACK包(SYN=1建邓,ACK=1,seg=Y睁枕,ack number=X+1)
3)最后A向B傳輸消息(ACK=1官边,seg=X+1,ack number=Y+1)
從步驟3)開始A就可以攜帶應(yīng)用層數(shù)據(jù)了外遇。- TCP是可靠的數(shù)據(jù)傳輸協(xié)議注簿,但在通過網(wǎng)絡(luò)通信的過程中可能丟失數(shù)據(jù)。請(qǐng)通過ACK和SEQ說明TCP通過何種機(jī)制保證丟失數(shù)據(jù)的可靠傳輸跳仿。
SEQ是當(dāng)前數(shù)據(jù)起始字節(jié)的序號(hào)诡渴,加入收到對(duì)方返回的ACK剛好是SEQ+數(shù)據(jù)大小(以字節(jié)為單位)菲语,則代表正確送達(dá)妄辩,可以繼續(xù)發(fā)送后續(xù)數(shù)據(jù)包惑灵。反之,在計(jì)時(shí)器超時(shí)后進(jìn)行重傳恩袱。- TCP套接字中調(diào)用write和read函數(shù)時(shí)數(shù)據(jù)如何移動(dòng)泣棋?結(jié)合I/O緩沖進(jìn)行說明。
write函數(shù)調(diào)用瞬間畔塔,數(shù)據(jù)將移至輸出緩沖;read函數(shù)調(diào)用瞬間鸯屿,從輸入緩沖讀取數(shù)據(jù)澈吨。- 對(duì)方主機(jī)的輸入緩沖剩余50字節(jié)空間時(shí),若本方主機(jī)通過write函數(shù)請(qǐng)求傳輸70 字節(jié)寄摆,請(qǐng)問TCP如何處理這種情況谅辣?
將70字節(jié)數(shù)據(jù)放入輸出緩沖,然后發(fā)送50字節(jié)到對(duì)方主機(jī)婶恼,待對(duì)方主機(jī)的輸入緩沖又有剩余時(shí)再發(fā)送后面的字節(jié)桑阶。- 第2章示例tcp_server.c和tcp_client.c中,客戶端接收服務(wù)器端傳輸?shù)淖址蟊阃顺觥勾邦,F(xiàn)更改程序蚣录,使服務(wù)器端和客戶端各傳遞1次字符串【炱考慮到使用TCP協(xié)議萎河,所以傳遞字符串前先以4字節(jié)整數(shù)型方式傳遞字符串長度。連接時(shí)服務(wù)器端和客戶端數(shù)據(jù)傳輸格式如下蕉饼。另外虐杯,不限制字符串傳輸順序及種類,但須進(jìn)行3次數(shù)據(jù)交換昧港。
代碼見附錄擎椰。0 0 0 6 H e l l o ? |-- 字符串長度 --|------ 字符串?dāng)?shù)據(jù) ------|
# gcc tri_server.c -o tserver # ./tserver 9191 Connected client 1 Message from client: Hello? Input message: Hi! Message from client: This is Xiao. Input message: I'm Yao. Message from client: Nice to meet you! Input message: Me, too.
# gcc tri_client.c -o tclient # ./tclient 127.0.0.1 9191 Connected Input message: Hello? Message from server: Hi! Input message: This is Xiao. Message from server: I'm Yao. Input message: Nice to meet you! Message from server: Me, too.
- 創(chuàng)建收發(fā)文件的服務(wù)器端/客戶端,實(shí)現(xiàn)順序如下创肥。
a. 客戶端接受用戶輸入的傳輸文件名达舒。
b. 客戶端請(qǐng)求服務(wù)器端傳輸該文件名所指文件。
c. 如果指定文件存在瓤的,服務(wù)器端就將其發(fā)送給客戶端休弃;反之,則斷開連接圈膏。
代碼見附錄塔猾。# gcc file_server.c -o fserver # ./fserver 9190 Connected client
# gcc file_client.c -o fclient # ./fclient 127.0.0.1 9190 Connected Input file name: exercise6
我的問題
- 把int存到char型數(shù)組中后發(fā)生了什么?
- fgetc(stdin)的作用稽坤?
刪除stdin中的"\n"字符丈甸,因?yàn)榍懊孀x取操作數(shù)的時(shí)候糯俗,最后有一個(gè)回車,他不能被當(dāng)做運(yùn)算符讀進(jìn)來睦擂。而前面讀操作數(shù)之前為什么不fgetc一下呢得湘?因?yàn)樽x取的是%d,它會(huì)自動(dòng)找到整數(shù)來讀取顿仇,忽略先導(dǎo)的空白符(指空格符淘正、制表符、回車符)臼闻。但當(dāng)讀取的是%c的時(shí)候鸿吆,scanf把緩沖區(qū)的第一個(gè)字符返回回去,不管是什么述呐,所以如果不fgetc就會(huì)讀取出“\n”惩淳。 - seq與ack number的關(guān)系?
書中的seq與ack number有錯(cuò)誤乓搬。以圖5-4為例進(jìn)行改正思犁。
A B
| --- seq 1200 (100 bytes data) --> |
| <-- ack number 1300 --- |
| --- seq 1300 (100 bytes data) --> |
| <-- ack number 1400 --- |
- C語言如果不初始化局部整型變量,里面的值是什么进肯?
與編譯器有關(guān)激蹲。對(duì)GCC來說,局部整型變量里的值是隨機(jī)的坷澡。所以初始化是必需的托呕。 - 為什么要用fgets讀取用戶輸入,而不是scanf频敛?
scanf遇空白符(空格项郊、回車、制表符)即終止讀取斟赚,無法一次性讀取完整的一個(gè)句子着降。而fgets每次讀取一行。
附錄
[1] 關(guān)于int整數(shù)轉(zhuǎn)換存儲(chǔ)到字符數(shù)組
[2] scanf用法及scanf中有\(zhòng)n的問題
[3] TCP連接建立的三次握手過程可以攜帶數(shù)據(jù)嗎拗军?
[4] Github