linux聊天室知識點整理

2021-09-10 01:53:33 字數 4148 閱讀 9367

標籤: linuxc

函式原型:int pthread_create(pthread_t *tid, const pthread_attr_t *tattr, void*(*start_routine)(void *), void *arg);
功能:建立乙個新的執行緒,並將執行緒加入當前程序返回值:

在呼叫成功完成之後返回零。其他任何返回值都表示出現了錯誤。如果

檢測到以下任一情況,pthread_create() 將失敗並返回相應的值。

eagain

描述: 超出了系統限制,如建立的執行緒太多。

einval

描述: tattr 的值無效

埠包括物理埠和邏輯埠。物理埠是用於連線物理裝置之間的介面,邏輯埠是邏輯上用於區分服務的埠。

我們寫聊天室小專案自然是用的是邏輯埠。

我們知道,一台擁有ip位址的主機可以提供許多服務,比如web服務、ftp服務、smtp服務等,這些服務完全可以通過1個ip位址來實現。那麼,主機是怎樣區分不同的網路服務呢?顯然不能只靠ip位址,因為ip 位址與網路服務的關係是一對多的關係。實際上是通過「ip位址+埠號」來區 分不同的服務的。

tcp/ip將埠號分為兩部分,一部分是保留埠即上述知名埠範圍為0-1023由權威機構規定其用途,如編號為80的tcp埠由ftp協議專用等,其餘的為自由埠,使用者程序可以自由申請並使用。

(我能不能說埠號就像是類似於芝麻開門的暗號?只不過有些是「公號」)

可以用「netstat -n」命令,以數字格式顯示位址和埠資訊。

套接字是一種通訊機制,憑藉這種機制,客戶/伺服器系統的開發工作既可以在本地單機上進行,也可以跨網路進行。

套接字的建立和使用與管道是有區別的,因為套接字明確地將客戶和伺服器區分出來,套接字可以實現將多個客 戶連線到乙個伺服器。

int socket(int domain,int type,int protocol);

建立的套接字是一條通訊線路的乙個端點

命名套接字

要想讓通過socket呼叫建立的套接字可以被其它程序使用,伺服器程式就必須給該套接字命名,如下,af_inet套接字就會關聯到乙個ip埠號

int bind(int socket,const struct sockaddr *address,size_t address_len);

bind系統呼叫把引數address中的位址分配給與檔案描述符socket關聯的未命名套接字

建立套接字佇列

為了能夠在套接字上接受進入鏈結,伺服器程式必須建立乙個佇列來儲存未處理的請求,它用listen系統呼叫來完成這一工作

int listen(int socket,int backlog);

linux系統可能會對佇列中未處理的連線的最大數目做出限制

接受連線

一旦伺服器程式建立並命名套接字之後,他就可以通過accept系統呼叫來等待客戶建立對該套接字的連線

int accept(int socket,struct sockaddr *address,size_t *address_len);

accept函式將建立乙個新套接字來與該客戶進行通訊,並且返回新套接字描述符(這個描述符和客戶端中描述符是一樣等同)

請求連線

客戶程式通過乙個未命名套接字和伺服器監聽套接字之間建立的連線的方法來連線到伺服器,如下:

int connect(int socket,const struct sockaddr *address,size_t address_len);

引數socket指定的套接字將連線到引數address指定的伺服器套接字

關閉套接字

你可以通過呼叫close函式來終止伺服器和客戶上的套接字連線

套接字通訊

套接字可以通過呼叫read(),write()系統呼叫來進行傳輸資料

一、因為tcp是面向連線的,所以在寫基於tcp伺服器的**時,要有listen套接字和accept套接字,而基於udp模型的**,並且udp客戶端直接呼叫 recvfrom/sendto 直接通訊即可,不用呼叫connect函式,這也分別體現出了它們的特性tcp面向連線,而udp則是無需連線。

二、對於recv在網路通訊中,因為tcp是基於位元組流的,所以每次recv上來的資料都是乙個資料段。可能你在這裡發了乙個1024位元組的資料,到了運輸層可能分段,所以對端可能不會一次性對上來1024位元組的資料。所以由此看出來recv每次讀socket檔案時,都讀的是乙個資料段。

解決方案:封裝函式recv,自定義乙個讀取資料的函式my_recv

/*

*函式名:my_recv

*描述:從套接字上讀取一次資料(以'\n'為結束的標誌)

*引數:conn_fd ————從該連線套接字上接收資料

* data_buf ————讀取到的資料儲存到此快取中

* len ————data_buf所指向的空間長度

*返回值:出錯返回-1,伺服器已關閉連線則返回0,成功返回讀取的位元組數

*/int my_recv(int conn_fd, char *data_buf, int len)

//從自定義緩衝區中讀取一次資料

for(i=0; *pread != '\n'; i++)

//去除結束標誌

len_remain--;

pread++;

return i; //讀取成功

}

實際上就是將套接字緩衝區的資料拷貝到自定義緩衝區,再按照格式(本**是以』\n』為結束標誌)讀取資料。

當然也可以自己在傳送時自己選擇定義結束標誌,目的是為了傳送方與接收方都能知道約定傳送的包到**結束了,到底這個包接收的是否完整。

三、對於阻塞socket而言,send呼叫的時候,當我們把應用層的資料拷貝到核心緩衝區的時候,如果核心緩衝區已滿,那麼就會阻塞,從send 函式返回也並不代表,資料傳送到了對端,只是代表了資料已經拷貝到了核心緩衝區。

四、send成功返回,對於 tcp來講只是應用層資料被拷貝到了核心傳送緩衝區中,對於 udp來講只是資料被加入到了 資料鏈路層佇列中。

五、connect呼叫失敗後,並不可以直接重用該socket,重用前需 close再用,因為基於 tcp狀態轉換圖得知 , connect 函式其實就是三次握手,那麼當三次握手失敗的話,socket 不是處於 closed 而是syn_sent狀態,所以我們必須重新關閉才能再次使用該 socket。

六、標題如何實現檔案傳輸,如果檔案較大如何解決

伺服器端 把大檔案分包 每乙個包大小建立乙個socket(對應乙個執行緒)進行傳輸

2.客戶端 對每乙個包對應乙個執行緒(同時對應乙個socket)進行接收

3.在傳送每乙個包時 包前要傳送這個包的大小 和對應的偏移量

4.在32位系統中要開啟大檔案的巨集開關

5.利用pread pwrite 可以保證原子操作 七、

有時我們不想server主動斷開連線後由於time_wait,而不能立即重啟,所以就想重新繫結相同的位址的server。

那麼為了埠復用需滿足以下條件其中之一:

1.socket繫結的不是同一網絡卡可以繫結

2.設定了 so_reuseaddr並且不能是linten狀態的節點

可見如果是處於time_wait的節點,我們只需提前設定 so_reuseaddr即可埠復用,解決server不能立刻重啟。

八、終止連線函式

int close(int socketfd)

首先如果我們要正常終止連線的話就需要呼叫close函式,呼叫時只有對應的socketfd 對應的檔案描述符對應的 file struct 結構體的引用計數為1的時候,呼叫才會觸發正常的四次揮手否則只是引用計數減1.

九、 close函式在伺服器上需要注意的點:

1.多程序程式別忘了在fork之後,父程序關閉 accept的返回的socket,子程序別忘了關閉listensocket,否則會因為引用計數的原因無法正常觸發終止序列。(fin)

2.收到fin段後需要即使呼叫close函式去關閉該socket,否則多路復用的機制(epoll)一直會提示該socket讀就緒。

(感覺沒寫完留個坑…)

linux 聊天室 知識點

一 具體操作 1.登陸虛擬機器 ubutu 賬號 root 密碼root 2.開啟多個視窗 快捷鍵 ctrl alt t 3.開啟伺服器 server 4.設定本地ip位址 ifconfig eth0 192.168.1.1 檢視ip位址 ifcofig 將網絡卡禁用 ifconfig eth0 d...

C Socket聊天室(小白整理)

最近算是0基礎學了socket的程式設計,發現很多不友好。其實是自己不知道,啊哈哈。最開始建立c 的指令碼時要建立窗體,而不是控制台程式。之後建議根據介面,自己來寫。還有別忘了server和client建立兩個程式哦。分別為服務端,客戶端。正式的socket服務端 public partial cl...

知識點整理

一 標準庫容器和演算法 1.順序容器 與前面類似 2.關聯容器 map和multimap 元素包含key 鍵 和值 value 兩部分 按照鍵對元素排序 map不允許重複元素出現,但multimap可以 set和multliset 是包含已排序物件的關聯容器 只是單純的鍵的集合 set不允許重複鍵出...