好的,下面是关于 TCP 套接字编程的一些常用函数的详细解释和示例,以及它们在实际应用中的作用。
1. 套接字创建和管理
1.1 socket()
- 功能: 创建一个新的套接字,用于网络通信。
- 原型:
int socket(int domain, int type, int protocol);
- 参数:
domain
: 通信域,通常为AF_INET
(IPv4)或AF_INET6
(IPv6)。type
: 套接字类型,TCP 使用SOCK_STREAM
,UDP 使用SOCK_DGRAM
。protocol
: 一般为0,表示自动选择适合的协议。
示例:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
}
2. 地址绑定
2.1 bind()
- 功能: 将套接字与本地地址(IP 和端口)绑定,使得操作系统知道这个套接字应当监听哪个地址。
- 原型:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
示例:
struct sockaddr_in server_addr;
memset(&server_addr, '\0', sizeof(server_addr)); // 清零结构体
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_addr.s_addr = INADDR_ANY; // 所有可用接口
server_addr.sin_port = htons(PORT); // 转换端口号到网络字节序
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
}
3. 启动监听
3.1 listen()
- 功能: 设置套接字为监听状态,以接受传入连接。
- 原型:
int listen(int sockfd, int backlog);
- 参数:
backlog
: 最大等待连接队列长度。
示例:
if (listen(sockfd, SOMAXCONN) < 0) {
perror("listen failed");
}
printf("Server listening on port %d...\n", PORT);
4. 接受连接
4.1 accept()
- 功能: 从等待连接队列中接受一个连接请求,并返回一个新的套接字,用于与客户端通信。
- 原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
示例:
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len);
if (new_sockfd < 0) {
perror("accept failed");
}
数据发送和接收
send() 和 recv()
send()
- 功能: 向已连接的套接字发送数据。
- 原型:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
recv()
- 功能: 从已连接的套接字接收数据。
- 原型:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
示例:
char buffer[1024];
ssize_t len = recv(new_sockfd, buffer, sizeof(buffer), 0); // 接收数据
if(len > 0){
buffer[len] = '\0'; // 添加字符串结束符以便打印
printf("Received from client: %s\n", buffer);
}
const char *msg = "Hello from server!";
send(new_sockfd,msg,sizeof(msg),0); // 给客户端发消息
网络地址处理
使用以下函数可以进行 IP 地址格式转换:
inet_pton()
将点分十进制的 IP 地址转换为网络二进制格式。
inet_ntop()
将网络二进制格式的 IP 地址转换回点分十进制。
套接字选项设置
setsockopt()
用于设置特定的套接字选项,例如 SO_REUSEADDR 等,以允许多个进程重用同一地址。
完整示例代码总结:
综合以上所有步骤,一个基本的 TCP 服务端代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
int sockfd;
struct sockaddr_in server_addr;
// 创建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 初始化服务器地址结构体
memset(&server_addr, '\0', sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
// Bind 套接字
if (bind(sockfd,(struct sockaddr*)&server_adddr,sizeof(server_adddr))< O){
perror("Bind Failed");
close(sockfd)
exit(EXIT_FAILURE)
}
// 开始监听
if(listen(sockfd,SOMAXCONN)< O){
perro("Listen Failed");
close(sockfd)
exit(EXIT_FAILURE)
}
printf("Server Listening on Port %d ...\n",PORT)
while(1){
struct sockaddr_in client_address ;
socklen_t address_length=sizeof(client_address)
// 接受客户端连接
int new_socket=accept(sockfd,(struct sockaddr*)&client_address,&address_length);
if(new_socket< O ){
perro('Accept Failed') ;
continue;
}
char buffer[1024];
ssize_T length=recv(new_socket,buffee,sizeof(buffer)-O ,O )
if(length>O){
buffe[length]='\O';
printf('Received from client:%s\n',buffer)
}
const char*message="Hello From Server!";
send(new_socket,message,strln(message),O);
close(new_socket);
}
close(sokfdd);
return EXIT_SUCCESS;
}
此程序展示了 TCP 服务端如何创建、绑定、监听和接受来自客户端的数据。在实现时,可以根据需要对其进行扩展,比如添加多线程支持、错误处理等。
内容由零声教学AI助手提供,问题来源于学员提问