Linux:网络编程
1、概述
?
?
2、字節序
?雙字的意思:一個字節八位。兩個字節就是三十二位
一個十六進制要用四個二進制表示
對內存來說,一個字節可以存放01
01 放一個字節,02放一個字節,03放一個字節,04?放一個字節
LE是小端的意思
低序字節就是04
高字節就是01
3、socket編程步驟
?服務器的開發步驟 :
1、套接字是為了后面的網絡的操作提供一個基本對接的描述符的接口
(就像我們open 一個文件的fd 一樣)
2、通過網絡往外面走的通道已經建立好了(socket),但是這個通道是一個空白的通道,我們需要給這個通道添加一些信息(你的ip地址,端口號),把這個ip地址和端口號,綁定到套接字
?客戶端:
只要給我一個通道,讓我知道你的Ip 地址和端口號,調用connect()就可以鏈接
這個圖的connect()的鍵號應該放在listen()后面有人監聽,客戶端發起connect(),服務端accept()
客戶端建立連接。連接到服務端的時候,他們就建立數據的通道了,
你的 socket()通過bind()確定了Ip地址和端口號
四、linux 提供的API?簡析
1、創建套接字
?
socket函數有點像open函數,它的目標是返回一個int 型?,int 型也是一個文件描述符,只不過它是個網絡描述符,跟我們做文件描述符,有稍微的區別,但是他們的意義是相似的
我們后面對網絡的訪問,都是基于文件描述符操作的
一般如果我們用? AF_IENT 就配合SOCK_STREAM
如果第一個用AF_IENT
第二個用SOCK_STREAM
第三個寫0? ,就會自己分配 IPPROTO_TCP(你寫這個宏也可以,寫0也可以)
這就是第一步,創建套接字,創建套接字的時候,已經寫明我是用哪種協議連接的
2、為套接字添加信息
你創建的套接字是個空的東西 ,
bind()里面的參數
第一個跟fd的意思一樣,通過socket 的返回值的sockfd,就是我們的套接字描述符了
第二個是個結構體指針
第三個參數是第二個參數的長度
??一般用下面的
補充:地址轉化API
第一個函數:
第一個參數是字符串,第二個參數就是我們的ip
第二個函數:
比如我們的服務器接入到客戶的連接,我們想知道客戶端的ip地址怎么辦呢?
3、監聽
第二個參數,是監聽的總數
4、連接
?第二個參數是客戶端的地址,
第三個參數是客戶端地址的長度
補充:數據的收發
?
這個read 和write和我們文件的read write是一樣的
你可以用read 和write也可以用其他的函數
?flags一般作為控制,是否有阻塞
其實除了這些還有呢
后面兩套一般用于udp 的連接的
tcp一般用read(),write()? ? 和recv()/send()
send() 發送 recv()接收
5、客戶端的connect函數
?第一個參數 客戶端socket()出來的文件描述符
第二個參數服務器的ip地址和端口號
第三個參數是整個地址的大小
五、socket服務端的代碼實現
1、 創建套接字
返回值:
成功,返回一個新的套接字描述符,錯誤返回負1
?創建套接字的代碼實現
2、?為套接字添加信息
?
那么sockadr_in 里面有哪些結構呢?
你可以在 usr/include底下搜索
?
?
記得空格然后再大括號
這種方式能搜到它定義的地方
在當前目錄底下遞歸的來找
r:是遞歸的意思
n:是找出來顯示行號
i:是不區分大小寫
(找到一個頭文件)
然后我們再來看看里面的184行
?端口號一般高于5000,小于3000是操作系統用的
作為用戶一般用5000 到9000之間比較多
這個端口號會傳到網絡上去,我們必須調用某個函數,把他變成網絡字節序
h是主機的意思
n是網絡的意思
s代表短的意思
l代表長的意思
看看需要啥頭文件
?有時候需要轉化一下地址,要不然機器不認識
找一下地址轉化的頭文件
?????????????????
?
記得bind()第二個參數強制轉化
注意:第一個參數要一個字符串,第二個參數要一個指針
inet_aton的第二個參數取地址
?
3、監聽和連接
當listen 沒有收到數據的時候,accept會卡在那里
accept的返回值是一個新的建立的socket的通道。
我們通過套接字連接到這個客戶端了,后續的連接選項的操做用accept 的返回值操作
之前的s_fd 可能還要接受別人的連接,一但連上以后,我們就先用c_fd操作
?
整體的思路:1、調用socket創建一個套接字
? ? ? ? ? ? ? ? 2、配置那些東西的時候,首先是協議,
????????????????????????第二個是端口號,端口號要注意字節序????????
? ? ? ? ? ? ? ? ? ? ? ? 第三個是ip地址,ip地址要注意人眼和機器認識的不一樣
? ? ? ? ? ? ? ? ? ? ? ? 最終把你的ip地址和fd 綁定起來
? ? ? ? ? ? ? ? 3、listen 去監聽套接字,這里面監聽了10個套接
??????????????????4、accept沒連接連上的時候,他會卡在這里
寫個while(1)不讓他退出,當有數據連上來的時候,打印一句話
如何驗證寫的是成功的還是不成功的呢?
可以在命令提示符下ping 一下,看一看地址能不能通
(雖然是臺虛擬機,可是從軟件層面上來說,還是兩臺不一樣的電腦)
地址能通
?
?然后再用telnet
如果我們端口號寫錯了,寫成7777
連接失敗
記得先運行程序?
?這就是連接成功的
?這樣是因為,咱們沒有對數據的收發做操作
4、補充
上面的listen 一但配置完就會很快的結束的,程序會卡在accept那邊
listen 只是告訴內核,我的這個服務器可以監聽10個,10個里面有已經完成三次握手的和正在完成三次握手的,有兩個隊列合計是10個
accept會去判斷你這個隊列是否存在已經完成三次握手的客戶端,已經完成三次握手的客戶端,accept就會繼續往下走,跟那個客戶端進行連接,通過accept的返回值和客戶端連接
我們來改一下上面的代碼
首先我們想要獲取客戶端的信息,然后打印window的地址
memset做數據的清空
?運行的結果
?用telnet連接
?
?這就是連接上了
連接上以后我們做數據的交互
定義一個readBuf來收取數據
從c_fd里面讀,讀到readBuf里面,讀128個字節
讀到以后再給人回復一下(理論上計算一下回復的長度)
?
運行一下,連接成功后按個s試試
?發現是個cmd那面變成了亂碼
?
會不會是cmd 的問題呢?
再用虛擬機試試,先連接
?
?在傳輸信息
?發現還是亂碼
?原因是,我們發送的數據量太多了
改動一下:定義一個字符串
?
運行一下,先連接上
?然后打一句話試試
?
?六、socket客戶端的代碼實現
?第一個是fd,
第二個是指針
第三個是大小
客戶端的代碼實現
?運行結果
先運行server 會自己卡在那里?
?等著client運行的時候server 也會運行
?
?7、實現雙方聊天
作為服務器我們不希望執行一次就退出
首先呢,如果我們的端口經常被占用,我們可以傳參來配置端口
傳進來的是字符串,我們要把ASCLL轉化成整型數
客戶端現在也是只寫一次,多次的一會再改
服務端的代碼
?
?客戶端的代碼
?
運行結果
并且我的服務端不會退出,支持多次連接
運行一次的結果
?運行好幾次的結果
得出的結論
我的服務端不會退出,支持多次連接
我們可以試試cmd 環境下
連接后按一下s試試
這就實現了我們想要的效果:服務器接入多少個都不會退出
?
那么現在我想實現父進程和子進程聊天、
客戶端:
子進程先改,connect以后我們不想讓他退出,就做個while(1)循環,讓父進程一直讀
讀的時候沒數據會一直阻塞,寫的話,我想有空就寫,我可以不斷創建子進程來寫
服務端也改一下
if(fork() ==0)代表進入子進程
有新客戶端進入的時候,調用子進程,子進程在這面等待讀取對方的數據
等待之前先fork一下,目的是在這邊去輸入
記得加參數的判斷
?
?運行的結果
先連接上
然后運行?
?運行一遍可以,但是運行多了就不會接收數據
思路:
有數據進來的時候,我創建一個子進程操作,子進程我希望他干兩件事,同時執行兩個while(1)
(想要執行兩個while(1)要么用線程,要么用fork創建子進程,才能讓兩個while(1)同時跑)
這個能一直往套接字里面發送,同時還能讀取套接字里面的信息
?
?
?
?
客戶端的也修改一下
?
?
?
運行的結果:
可以正常的聊天了
?
?八、多方消息收發
我們實現自動回復,我們不實現獲取用戶的輸入
(對我們來說,客戶端1 客戶端2 共用一個光標)
我們做一個mrck 按連接進來的順序,標記一下,當我收到一個連接的時候,讓mark++
現在服務端的功能,只能接收每一個客戶端發上來的消息,
做個子進程每隔三秒給客戶端發一句話,我就知道客戶端的消息有沒有丟失
對服務端來說呢?都能收到客戶端的請求的
?
?
?
運行結果
這邊每隔三秒就會收到welcome NO1
?
?
?
總結
以上是生活随笔為你收集整理的Linux:网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux:线程
- 下一篇: 静态体验红旗HQ9,气势拉满豪华十足,但