Linux Socket 函數庫是從 Berkeley 大學開發的 BSD UNIX 系統中移植過來的。BSD Socket 接口是在眾多 Unix 系統中被廣泛支持的 TCP/IP 通信接口,Linux 下的 Socket 程序設計,除了微小的差別之外,也適用於大多數其它 Unix 系統。
Socket 的使用,和文件操作比較類似。如同文件的讀、寫、打開、關閉等操作一樣,TCP/IP 網絡通信同樣也有這些操作,不過它使用的接口不是文件描述符或者 FILE*,而是一個稱做 Socket 的描述符。類似於文件操作,對於 Socket,也通過讀、寫、打開、關閉操作來進行網絡數據傳送。同時,還有一些輔助的函數,如域名/IP 地址查詢、Socket 功能設置等。
這星期的實驗是Socket編程實驗,我將自己的套在框架下寫的代碼分享出來。一份是TCP代碼,sender向receiver發送"hello",receiver將"hello"原封不動發回去,sender接收到"hello"后斷開連接,兩個服務同時down。第二份是UDP代碼,receiver監聽自己的端口,sender向receiver發送0-8的整數,receiver不會對收到了的信息作確認。發送完畢后sender down,receiver會繼續監聽。
閱讀接下來的代碼需要對Socket中的函數,Socket標志符等概念十分清楚,其中一份TCP代碼經過了詳細的注釋。bind(),listen(),send()......這些Socket庫中的函數都需要讀者提前了解他們的功能。
放出一份TCP Receiver的代碼,其余的代碼在文末可以下載。
1 #include <stdio.h> 2 #include <string.h> 3 //數據格式轉換 4 #include "net_exp.h" 5 #include <netinet/in.h> 6 7 main(){ 8 //TCP/IP中專用的用於監聽連接請求的本地地址 9 struct sockaddr_in client, server; 10 int s,ns,namelen,pktlen; 11 char buf[256]; 12 //定義套接字,返回值是Socket描述符 13 s = socket(AF_INET, SOCK_STREAM, 0); 14 //將指針當前位置后面的sizeof(server)個字節清0 15 memset((char*)&server, 0, sizeof(server)); 16 //Address family 17 server.sin_family = AF_INET; 18 //Port number,轉換成unsigned short int 19 server.sin_port = htons(TCP_SERVER_PORT); 20 server.sin_addr.s_addr = INADDR_ANY; 21 //給已經打開的socket指定本地地址,注意看,傳參數的時候有類型轉換 22 bind(s, (struct sockaddr*)&server, sizeof(server)); 23 //s-Socket描述符,backlog-連接請求暫存隊列長度, 24 //調用listen系統將給此Socket配備一個連接請求的隊列,暫存系統接收到的、申請向此Socket建立連接的請求。 25 listen(s, 1); 26 namelen = sizeof(client); 27 //accept:接受指定Socket上的連接請求,返回一個新的socket標識符,相當於創建了一個新的Socket用於傳輸數據, 28 //原來的Socket仍用來監聽請求。 29 ns = accept(s, (struct sockaddr*)&client, &namelen); 30 for(;;){ 31 //接收ns上受到的數據,存入buf 32 pktlen = recv(ns, buf, sizeof(buf), 0); 33 if(pktlen==0) 34 break; 35 printf("Received line:%s\n", buf); 36 //向發送方返回一模一樣的數據 37 send(ns, buf, pktlen, 0); 38 } 39 close(ns); 40 close(s); 41 }
想自己修改功能的話,修改源碼按照我最近寫的一個隨筆重新編譯即可。比如實現兩個終端或者兩個主機聊天。
源碼,可執行程序:https://files.cnblogs.com/files/chester-cs/Socket.zip