socket函數
它用于創建一個新的套接字(socket)。
函數原型
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
參數解釋
domain
:它指定了通信所使用的協議族,常見的取值如下:????????
AF_INET
:代表 IPv4 協議。????????
AF_INET6
:代表 IPv6 協議。????????
AF_UNIX
或AF_LOCAL
:用于本地(Unix 域)套接字通信。
type
:它指定了套接字的類型,常用的類型有:????????
SOCK_STREAM
:表示面向連接的、可靠的 TCP 套接字。????????
SOCK_DGRAM
:表示無連接的、不可靠的 UDP 套接字。????????
SOCK_RAW
:允許程序直接訪問底層協議,如 IP、ICMP 等。
protocol
:通常設置為 0,表示讓系統根據domain
和type
自動選擇合適的協議。
返回值
????????若函數調用成功,會返回一個新的套接字描述符(非負整數),后續的網絡操作會用到這個描述符。
????????若調用失敗,會返回 -1,并設置
errno
來指示具體的錯誤原因。
示例
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>using namespace std;int main()
{// 初始化網絡 int socketfd = socket(AF_INET, SOCK_STREAM, 0);if (socketfd < 0){/*可能情況 *1、沒有連接網絡 *2、網卡壞了*/perror("socket error");}else{cout << "服務器網絡初始化 socketfd=" << socketfd << endl;}return 0;
}
?結果
?bind函數
????????用于將一個套接字(socket)與特定的網絡地址和端口號綁定在一起。
函數原型
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數解釋
????????
sockfd
:這是由socket
函數返回的套接字描述符,代表要進行綁定操作的套接字。????????
addr
:指向一個sockaddr
類型的結構體指針,該結構體包含了要綁定的地址和端口信息。不過在實際使用中,通常會使用具體的地址結構體,如struct sockaddr_in
(用于 IPv4)或struct sockaddr_in6
(用于 IPv6),然后進行強制類型轉換。????????
addrlen
:表示addr
所指向的結構體的長度。補(struct sockaddr_in):
#include <netinet/in.h>struct sockaddr_in {sa_family_t sin_family; // 地址族,通常是 AF_INET(IPv4)in_port_t sin_port; // 端口號,使用網絡字節序(大端序)(服務器系統默認IP地址:INADDR_ANY)struct in_addr sin_addr; // IPv4 地址,使用網絡字節序unsigned char sin_zero[8]; // 填充字段,使其大小與 struct sockaddr 相同,一般設置為全 0 };
返回值
????????若綁定成功,返回 0。
????????若失敗,返回 -1,并設置
errno
來指示具體的錯誤原因。
listen函數
????????主要用于將一個套接字(socket)設置為監聽狀態,以便接收客戶端的連接請求。?
函數原型
#include <sys/socket.h>
int listen(int sockfd, int backlog);
參數解釋
????????
sockfd
:這是一個由socket
函數返回的套接字描述符,代表要設置為監聽狀態的套接字。該套接字必須已經通過bind
函數綁定到了一個特定的地址和端口。????????
backlog
:指定了允許在隊列中等待處理的最大連接請求數量。當有多個客戶端同時發起連接請求時,服務器無法立即處理所有請求,這些請求會被放入一個隊列中等待處理。backlog
的值決定了這個隊列的最大長度。不同系統對backlog
的最大值有不同的限制,一般來說,常見的值可以設置為 5 或 10。
返回值
????????若函數調用成功,返回 0。
????????若調用失敗,返回 -1,并設置
errno
來指示具體的錯誤原因。
accept函數?
????????主要用于服務器端,它會讓服務器處于阻塞狀態,等待客戶端的連接請求。一旦接收到客戶端的連接請求,accept
函數就會返回一個新的套接字描述符,這個描述符用于和客戶端進行數據通信。而原來的套接字描述符依舊負責監聽新的連接請求。
函數原型
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
參數解釋
????????
sockfd
:這是一個已經處于監聽狀態的套接字描述符,它是通過socket()
創建,再由bind()
綁定地址和端口,最后使用listen()
開始監聽的套接字。????????
addr(前面設置過的化一般為NULL)
:這是一個指向sockaddr
結構體的指針,該結構體用于存儲客戶端的地址信息。在實際使用時,通常會使用sockaddr_in
(用于 IPv4)或sockaddr_in6
(用于 IPv6)結構體,然后進行類型轉換。????????
addrlen(前面設置過的化一般為NULL)
:這是一個指向socklen_t
類型的指針,它表示addr
所指向的結構體的長度。在調用accept
之前,需要將其初始化為addr
結構體的大小;調用完成后,該指針指向的值會被更新為實際存儲的客戶端地址信息的長度。
返回值
????????若調用成功,
accept
會返回一個新的套接字描述符,此描述符用于和客戶端進行數據通信。原來的sockfd
仍然用于監聽新的連接請求。????????若調用失敗,會返回 -1。
整合示例
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>using namespace std;int main()
{struct sockaddr_in addr;int length = 0;int acceptfd = 0;// 初始化網絡 int socketfd = socket(AF_INET, SOCK_STREAM, 0);if (socketfd < 0){/*可能情況 *1、沒有連接網絡 *2、網卡壞了*/perror("socket error");return 0;}else{addr.sin_family = AF_INET;// 服務器系統默認IP地址addr.sin_addr.s_addr = INADDR_ANY;addr.sin_port = htons(10001);length = sizeof(addr);// 綁定端口號if (bind(socketfd, (struct sockaddr*)(&addr), length) == -1){perror("bind error");return 0;}// 監聽這個文件描述符,是否有客戶端來連接if (listen(socketfd, 10) == -1){perror("lister error");return 0;}cout << "服務器網絡搭建成功" << endl;// 因為服務器24h長時間開機while (1){// acceptfd代表已經連接成功的客戶端// 阻塞式函數(等待客戶端的到來)acceptfd = accept(socketfd, NULL, NULL);cout << "客戶端上線,acceptfd=" << acceptfd << endl;}}return 0;
}