在C語言中,套接字(Socket)編程主要用于網絡通信,尤其是在基于TCP/IP協議的應用程序開發中。常用的套接字編程API主要基于Berkeley Sockets(伯克利套接字)接口,這些函數通常在<sys/socket.h>
和<netinet/in.h>
頭文件中定義。以下是對常見套接字API的詳細講解,包括函數功能、參數、返回值、涉及的結構體及其成員的含義。
1. socket()
功能
創建新的套接字。
函數原型
int socket(int domain, int type, int protocol);
參數
domain
: 指定通信協議族(協議域)。- 類型:
int
- 常見值:
AF_INET
(IPv4協議)AF_INET6
(IPv6協議)AF_UNIX
(本地通信)
- 含義: 定義套接字的地址格式和通信范圍。
- 類型:
type
: 指定套接字類型。- 類型:
int
- 常見值:
SOCK_STREAM
(面向連接的TCP流)SOCK_DGRAM
(無連接的UDP數據報)SOCK_RAW
(原始套接字)
- 含義: 定義通信的語義。
- 類型:
protocol
: 指定具體協議。- 類型:
int
- 常見值:
- 通常為
0
(表示由domain
和type
自動選擇默認協議,如TCP或UDP) - 特殊值(如
IPPROTO_TCP
、IPPROTO_UDP
)用于顯式指定協議。
- 通常為
- 含義: 細化協議選擇。
- 類型:
返回值
- 類型:
int
- 含義:
- 成功: 返回套接字文件描述符(非負整數)。
- 失敗: 返回
-1
,并設置errno
表示錯誤。
相關結構體
無直接結構體參數。
2. bind()
功能
將套接字綁定到特定的地址和端口。
函數原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數
sockfd
: 要綁定的套接字文件描述符。- 類型:
int
- 含義: 由
socket()
創建的套接字。
- 類型:
addr
: 指向地址結構體的指針。- 類型:
const struct sockaddr *
- 含義: 指定綁定的地址和端口。
- 類型:
addrlen
: 地址結構體的大小。- 類型:
socklen_t
(通常是unsigned int
) - 含義:
addr
指向的結構體長度。
- 類型:
返回值
- 類型:
int
- 含義:
- 成功: 返回
0
。 - 失敗: 返回
-1
,并設置errno
。
- 成功: 返回
相關結構體
struct sockaddr
- 定義:
struct sockaddr {sa_family_t sa_family; // 地址族char sa_data[14]; // 地址數據(具體含義依賴地址族) };
- 成員:
sa_family
: 地址族(如AF_INET
)。- 類型:
sa_family_t
(通常是unsigned short
) - 含義: 指定地址類型。
- 類型:
sa_data
: 地址數據的字節數組。- 類型:
char[14]
- 含義: 存儲具體地址信息,但通常不直接使用。
- 類型:
- 定義:
- 實際常用:
struct sockaddr_in
(針對IPv4)- 定義:
struct sockaddr_in {sa_family_t sin_family; // 地址族in_port_t sin_port; // 端口號struct in_addr sin_addr; // IP地址unsigned char sin_zero[8]; // 填充字節 };
- 成員:
sin_family
: 地址族。- 類型:
sa_family_t
- 含義: 通常為
AF_INET
。
- 類型:
sin_port
: 端口號。- 類型:
in_port_t
(通常是uint16_t
) - 含義: 網絡字節序的端口號(如
htons(8080)
)。
- 類型:
sin_addr
: IP地址。- 類型:
struct in_addr
- 定義:
struct in_addr {in_addr_t s_addr; // IPv4地址(32位) };
- 成員:
s_addr
: IPv4地址。- 類型:
in_addr_t
(通常是uint32_t
) - 含義: 網絡字節序的IP地址(如
inet_addr("127.0.0.1")
)。
- 類型:
- 類型:
sin_zero
: 填充字節。- 類型:
unsigned char[8]
- 含義: 用于對齊,通常置為
0
。
- 類型:
- 定義:
3. listen()
功能
將套接字設置為監聽狀態,用于接受客戶端連接(僅限TCP)。
函數原型
int listen(int sockfd, int backlog);
參數
sockfd
: 要監聽的套接字文件描述符。- 類型:
int
- 含義: 已綁定的服務器套接字。
- 類型:
backlog
: 等待連接隊列的最大長度。- 類型:
int
- 含義: 指定未完成連接的最大排隊數(如
5
或10
)。
- 類型:
返回值
- 類型:
int
- 含義:
- 成功: 返回
0
。 - 失敗: 返回
-1
,并設置errno
。
- 成功: 返回
相關結構體
無直接結構體參數。
4. accept()
功能
接受客戶端連接請求,返回新的套接字用于通信(僅限TCP)。
函數原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
參數
sockfd
: 監聽的套接字文件描述符。- 類型:
int
- 含義: 已調用
listen()
的服務器套接字。
- 類型:
addr
: 客戶端地址信息。- 類型:
struct sockaddr *
- 含義: 用于存儲連接的客戶端地址(通常轉換為
struct sockaddr_in
)。
- 類型:
addrlen
: 地址結構體的長度。- 類型:
socklen_t *
- 含義: 傳入時為
addr
的大小,函數返回時為實際地址長度。
- 類型:
返回值
- 類型:
int
- 含義:
- 成功: 返回新的套接字文件描述符,用于與客戶端通信。
- 失敗: 返回
-1
,并設置errno
。
相關結構體
- 同
bind()
中的struct sockaddr
和struct sockaddr_in
。
5. connect()
功能
發起與服務器的連接(用于客戶端)。
函數原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數
sockfd
: 客戶端套接字文件描述符。- 類型:
int
- 含義: 由
socket()
創建的套接字。
- 類型:
addr
: 目標服務器地址。- 類型:
const struct sockaddr *
- 含義: 指定服務器的地址和端口。
- 類型:
addrlen
: 地址結構體的長度。- 類型:
socklen_t
- 含義:
addr
的大小。
- 類型:
返回值
- 類型:
int
- 含義:
- 成功: 返回
0
。 - 失敗: 返回
-1
,并設置errno
。
- 成功: 返回
相關結構體
- 同
bind()
中的struct sockaddr
和struct sockaddr_in
。
6. send()
和 recv()
功能
send()
: 發送數據。recv()
: 接收數據。
函數原型
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
參數
sockfd
: 套接字文件描述符。- 類型:
int
- 含義: 已連接的套接字。
- 類型:
buf
: 數據緩沖區。- 類型:
const void *
(send
)或void *
(recv
) - 含義: 發送或接收的數據存儲位置。
- 類型:
len
: 數據長度。- 類型:
size_t
- 含義: 要發送或接收的字節數。
- 類型:
flags
: 操作標志。- 類型:
int
- 常見值:
0
(默認行為)MSG_DONTWAIT
(非阻塞)
- 含義: 修改發送/接收行為。
- 類型:
返回值
- 類型:
ssize_t
- 含義:
- 成功: 返回實際發送/接收的字節數。
- 失敗: 返回
-1
,并設置errno
。
相關結構體
無直接結構體參數。
7. close()
功能
關閉套接字。
函數原型
int close(int sockfd);
參數
sockfd
: 要關閉的套接字文件描述符。- 類型:
int
- 含義: 由
socket()
或accept()
返回的描述符。
- 類型:
返回值
- 類型:
int
- 含義:
- 成功: 返回
0
。 - 失敗: 返回
-1
,并設置errno
。
- 成功: 返回
相關結構體
無直接結構體參數。
總結
以下是常用套接字API的快速參考表:
函數 | 功能 | 返回值類型 | 主要結構體 |
---|---|---|---|
socket() | 創建套接字 | int | 無 |
bind() | 綁定地址 | int | sockaddr , sockaddr_in |
listen() | 開始監聽 | int | 無 |
accept() | 接受連接 | int | sockaddr , sockaddr_in |
connect() | 發起連接 | int | sockaddr , sockaddr_in |
send() | 發送數據 | ssize_t | 無 |
recv() | 接收數據 | ssize_t | 無 |
close() | 關閉套接字 | int | 無 |
這些API是C語言網絡編程的核心,配合結構體(如struct sockaddr_in
)使用,可以實現基本的客戶端-服務器通信。需要注意網絡字節序(htons
, ntohs
, htonl
, ntohl
)和錯誤處理(errno
)的使用。