### C语言中Socket通信的详细解释和用法
C语言中的Socket通信是一种用于实现网络通信的技术,通过Socket可以实现不同主机之间的数据交换。以下是关于Socket通信的基本概念、函数以及一个完整的示例程序。
#### 1. 基本概念
在C语言中,Socket编程涉及几个关键步骤:创建套接字、绑定地址信息、监听连接请求、接受客户端连接、发送与接收数据以及关闭连接。这些步骤分别对应于不同的函数[^1]。
- **套接字(Socket)**:是应用程序与网络协议交互的一个端点。
- **协议族(Address Family)**:定义了使用何种协议进行通信,例如`AF_INET`表示IPv4协议[^3]。
- **端口(Port)**:用于标识计算机上的特定服务或应用。
#### 2. 关键函数
以下是一些常用的Socket函数及其作用:
- **socket()**: 创建一个新的套接字。
```c
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
```
参数说明:
- `AF_INET`: 使用IPv4协议。
- `SOCK_STREAM`: 表示TCP流式套接字。
- 第三个参数通常为0,表示自动选择合适的协议。
- **bind()**: 将套接字与本地地址绑定。
```c
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8989); // 端口号需要转换为网络字节序
server_addr.sin_addr.s_addr = inet_addr("192.168.5.20");
bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
```
- **listen()**: 设置服务器监听传入连接。
```c
listen(sockfd, 5); // backlog为5,表示最多允许5个等待连接
```
- **accept()**: 接受客户端连接。
```c
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
```
- **send() 和 recv()**: 用于发送和接收数据。
```c
send(new_sockfd, "Hello from server!", 19, 0);
char buffer[1024];
recv(new_sockfd, buffer, 1024, 0);
```
- **close()**: 关闭套接字。
```c
close(sockfd);
```
#### 3. 示例代码
以下是一个简单的服务器端和客户端的Socket通信示例。
##### 服务器端代码
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sockfd, new_sockfd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
// 创建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation error");
exit(EXIT_FAILURE);
}
// 配置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8989);
// 绑定地址
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(sockfd, 5) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
printf("Server is listening on port 8989...\n");
// 接受连接
if ((new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len)) < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
printf("Connection accepted from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 发送消息
const char *message = "Hello from server!";
send(new_sockfd, message, strlen(message), 0);
printf("Message sent to client.\n");
// 关闭连接
close(new_sockfd);
close(sockfd);
return 0;
}
```
##### 客户端代码
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[1024] = {0};
// 创建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation error");
exit(EXIT_FAILURE);
}
// 配置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8989);
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
perror("Invalid address/ Address not supported");
exit(EXIT_FAILURE);
}
// 连接到服务器
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
printf("Connected to server.\n");
// 接收消息
int valread = read(sockfd, buffer, 1024);
printf("Message from server: %s\n", buffer);
// 关闭连接
close(sockfd);
return 0;
}
```
#### 4. 注意事项
- 在实际开发中,需要对错误进行更详细的处理,确保程序的健壮性[^2]。
- 网络字节序与主机字节序不同,因此在设置端口号时必须使用`htons()`函数进行转换[^3]。