Socket 核心 API 流程
| 階段 | 服務端 | 客戶端 |
| 創建 | socket() | socket() |
| 綁定 | bind() | -- |
| 監聽 | listen() | -- |
| 連接 | accept() | connect() |
| 數據傳輸 | recv()/send() | send()/recv() |
| 關閉 | close() | close() |
客戶端完整代碼
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 3333
int main(int argc, char *argv[]) {
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
exit(1);
}
if ((host = gethostbyname(argv[1])) == NULL) {
fprintf(stderr, "Gethostname error\n");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "Socket Error: %s\n", strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
fprintf(stderr, "Connect Error: %s\n", strerror(errno));
exit(1);
}
printf("Please input char:\n");
fgets(buffer, 1024, stdin);
send(sockfd, buffer, strlen(buffer), 0);
close(sockfd);
return 0;
}
服務端完整代碼
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 3333
int main(int argc, char *argv[]) {
int sockfd, new_fd;
struct sockaddr_in server_addr, client_addr;
int sin_size, nbytes;
char buffer[1024];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "Socket error: %s\n", strerror(errno));
exit(1);
}
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
fprintf(stderr, "Bind error: %s\n", strerror(errno));
exit(1);
}
if (listen(sockfd, 5) == -1) {
fprintf(stderr, "Listen error: %s\n", strerror(errno));
exit(1);
}
while (1) {
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size)) == -1) {
fprintf(stderr, "Accept error: %s\n", strerror(errno));
exit(1);
}
fprintf(stderr, "Server get connection from %s\n", inet_ntoa(client_addr.sin_addr));
if ((nbytes = recv(new_fd, buffer, 1024, 0)) == -1) {
fprintf(stderr, "Read Error: %s\n", strerror(errno));
exit(1);
}
buffer[nbytes] = '\0';
printf("Server received: %s\n", buffer);
close(new_fd);
}
close(sockfd);
return 0;
}
關鍵點解析
- 字節序轉換:
htons/htonl(主機序→網絡序),ntohs/ntohl(網絡序→主機序)。
- INADDR_ANY:綁定所有本地 IP,允許任意介面接入。
- backlog:
listen(sockfd, 5) 中的 5 為內核等待隊列最大長度。
- 阻塞模式:默認
accept/recv 為阻塞,生產環境常配合 select/epoll 實現高併發。
- 錯誤處理:所有系統調用均需檢查返回值,使用
strerror(errno) 獲取可讀錯誤信息。
編譯與運行
# 服務端
gcc server.c -o server
./server
# 客戶端
gcc client.c -o client
./client 127.0.0.1