一、基於socket的一對一通信模型
1.1 相關函數的解析
(1)socket()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:
主要用於創建用於交流 / 通信的端點;
參數:
第一個參數:協議族/域,決定了本地通信還是網絡通信;
AF_UNIX / AF_LOCAL - - - - - 表示實現本地通信
AF_INET - - - - - - - - - - - - - - - -表示實現基於IPv4的網絡通信
第二個參數:具體的通信類型,決定了具體的通信協議;
SOCK_STREAM - - - - 提供有序的、可靠的、雙向的、面向連接的字節流通信方式,也就是基於TCP協議的通信方式
SOCK_DGRAM - - - - - 提供不可靠的,非面向連接的數據報通信方式,也就是基於UDP協議的通信方式
第三個參數:具體的特殊協議,默認給0即可;
返回值:
success —- 文件描述符,error —- -1;
(2)通信地址的常用地址數據類型
a. struct sockaddr類型 - - - - 主要用於函數的形參類型,基本不會定義結構體變量去使用;
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
}
b. struct sockaddr_un類型 - - - - 主要用於實現本地通信;
#include <sys/un.h>
struct sockaddr_un
{
sa_family_t sun_family; //協議族,和socket()的第一個實參保持一致即可;
char sun_path[]; //socket文件的路徑名;
}
c. struct sockaddr_in類型 - - - - 主要用於網絡通信;
#include <netinet/in.h>
struct sockaddr_in
{
sa_family_t sin_family; //協議族 AF_INET
in_port_t sin_port; //端口號
struct in_addr sin_addr; //IP地址
}
struct in_addr
{
in_addr_t s_addr; //整數類型的IP地址
}
(3)bind()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
主要用於綁定socket和指定的通信地址;
參數:
第一個參數:socket的描述符,socket()的返回值;
第二個參數:結構體指針,用於指定通信地址,需要進行類型轉換;
第三個參數:通信地址的大小,使用sizeof()計算即可;
(4)connect()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
主要用於建立socket到通信地址的連接,參數和返回值參考bind()即可;
(5)字節序轉換函數
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
/* 主要用於將32位二進制組成的主機字節序轉換爲網絡字節序 */
uint16_t htons(uint16_t hostshort);
/* 主要用於將16位二進制組成的主機字節序轉換爲網絡字節序 */
uint32_t ntohl(uint32_t netlong);
/* 主要用於將32位二進制組成的網絡字節序轉換爲主機字節序 */
uint16_t ntohs(uint16_t netshort);
/* 主要用於將16位二進制組成的網絡字節序轉換爲主機字節序 */
(6)IP地址的轉換函數
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
功能:
主要用於將字符串形式的IP地址轉換爲整數類型的IP地址;
char *inet_ntoa(struct in_addr in);
功能:
主要用於將結構體類型的IP地址轉換爲字符串類型;
二、基於TCP協議的網絡通信模型
2.1 通信模型
服務器:
(1)創建socket,使用socket();
(2)準備通信地址,使用結構體類型;
(3)綁定socket和通信地址,使用bind();
(4)監聽,使用listen();
(5)響應客戶端的連接請求,使用accept();
(6)進行通信,使用send()/recv();
(7)關閉socket,使用close();
客戶端:
(1)創建socket,使用socket();
(2)準備通信地址,使用服務器的地址;
(3)連接socket和通信地址,使用connect();
(4)進行通信,使用send()/recv();
(5)關閉socket,使用close();
2.2 相關函數的解析
(1)listen()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:
主要用於將參數sockfd所指定的socket標記爲被動的socket,也就是原來的socket是可以用於通信的,但是標記爲被動的socket之後,專門用於響應即將到來的連接請求,不再用於通信;
參數:
第一個參數:socket描述符,socket()的返回值;
第二個參數:主要用於指定懸而未決連接請求隊列的最大長度,當該隊列爲滿時,有客戶端發來連接請求,則會被拒絕;
(2)accept()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
主要用於響應指定socket上面的一個連接請求;該函數會提取懸而未決連接請求隊列中的第一個連接請求進行響應,響應的方式就是再創建一個連接好的socket進行通信;
參數:
第一個參數:socket的描述符,socket()的返回值;
第二個參數:結構體指針,用於帶出客戶端的通信地址;
第三個參數:指針類型,用於帶出客戶端通信地址的大小;
返回值:
success —- 通信socket的描述符,error —- -1;
(3)send()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
主要用於向指定的socket發送指定的數據內容;
參數:
第一個參數:socket描述符,用於通信的socket;
第二個參數:被髮送數據的首地址;
第三個參數:被髮送數據的大小;
第四個參數:發送的標誌,默認給0即可;
返回值:
success —- 實際發送數據大小,error —- -1;
(4)recv()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
主要用於接收參數指定socket中的數據;
參數:
第一個參數:socket描述符,用於通信的socket;
第二個參數:存放接收到數據的緩衝區首地址;
第三個參數:期望接收的數據大小;
第四個參數:接收的標誌,默認給0即可;
返回值:
success —- 實際接收數據大小,error —- -1;
練習:
使用基於tcp協議的通信模型實現一對多通信
a. 要求服務器可以不斷地響應客戶端的連接請求;
=> 使用while(1)無限循環
b. 要求服務器可以同時接收多個客戶端發來的消息;
=> 使用fork()創建子進程
c. 要求服務器可以和每一個客戶端不斷進行通信;
=> 使用while(1)無限循環
d. 要求當客戶端發來”bye”時,表示客戶端下線;
=> 使用strcmp()比較
e. 要求客戶端發送的消息由鍵盤輸入;
=> 使用scanf()/gets()/fgets()
f. 要求關閉服務器請按ctrl+c來實現;
=> 對信號SIGINT進行自定義處理
明日預報:
(1)網絡編程;
(2)多線程;