C 语言网络编程基础
外观
C语言网络编程基础[编辑 | 编辑源代码]
C语言网络编程是指使用C语言及相关库函数实现计算机之间的网络通信。它是系统编程和网络技术的结合,广泛应用于服务器开发、嵌入式设备通信、网络安全工具等领域。本节将介绍基础概念、核心API及实际应用案例。
核心概念[编辑 | 编辑源代码]
网络编程的核心是套接字(Socket),它是网络通信的端点,允许不同主机或同一主机的不同进程间交换数据。主要分为两类:
- 流式套接字(SOCK_STREAM):基于TCP协议,提供可靠、面向连接的通信
- 数据报套接字(SOCK_DGRAM):基于UDP协议,提供无连接的快速通信
基础API详解[编辑 | 编辑源代码]
创建套接字[编辑 | 编辑源代码]
使用socket()
函数创建通信端点:
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
示例创建TCP套接字:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
地址结构[编辑 | 编辑源代码]
网络地址使用sockaddr_in
结构体:
struct sockaddr_in {
sa_family_t sin_family; // 地址族,如AF_INET
in_port_t sin_port; // 端口号(网络字节序)
struct in_addr sin_addr; // IP地址
};
struct in_addr {
uint32_t s_addr; // 32位IP地址
};
服务器端流程[编辑 | 编辑源代码]
1. 绑定地址:bind()
2. 监听连接:listen()
3. 接受连接:accept()
示例服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BACKLOG 5
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, BACKLOG) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d\n", PORT);
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[1024] = {0};
read(new_socket, buffer, 1024);
printf("Message from client: %s\n", buffer);
char *hello = "Hello from server";
send(new_socket, hello, strlen(hello), 0);
close(new_socket);
close(server_fd);
return 0;
}
客户端流程[编辑 | 编辑源代码]
1. 连接服务器:connect()
2. 发送/接收数据:send()
/recv()
示例客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 转换IP地址
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}
send(sock, hello, strlen(hello), 0);
printf("Hello message sent\n");
read(sock, buffer, 1024);
printf("Server: %s\n", buffer);
close(sock);
return 0;
}
字节序转换[编辑 | 编辑源代码]
网络字节序(大端序)与主机字节序转换函数:
htons()
- 主机到网络(短整型)htonl()
- 主机到网络(长整型)ntohs()
- 网络到主机(短整型)ntohl()
- 网络到主机(长整型)
实际应用案例[编辑 | 编辑源代码]
简易聊天程序[编辑 | 编辑源代码]
结合多线程实现双向通信:
// 服务器端接收线程
void *receive_handler(void *socket_desc) {
int sock = *(int*)socket_desc;
char buffer[1024];
while (1) {
int read_size = recv(sock, buffer, sizeof(buffer), 0);
if (read_size > 0) {
buffer[read_size] = '\0';
printf("Client: %s", buffer);
}
}
return NULL;
}
// 主函数中创建线程
pthread_t recv_thread;
if (pthread_create(&recv_thread, NULL, receive_handler, (void*)&new_socket) < 0) {
perror("could not create thread");
return 1;
}
文件传输协议[编辑 | 编辑源代码]
实现基础文件传输功能:
// 发送文件函数
void send_file(FILE *fp, int sockfd) {
char data[1024] = {0};
while (fgets(data, sizeof(data), fp) != NULL) {
if (send(sockfd, data, sizeof(data), 0) == -1) {
perror("Error in sending file");
exit(1);
}
bzero(data, sizeof(data));
}
}
常见问题与调试[编辑 | 编辑源代码]
错误现象 | 可能原因 | 解决方案 |
---|---|---|
Address already in use |
端口被占用 | 使用setsockopt() 设置SO_REUSEADDR
|
Connection refused |
服务器未运行/防火墙阻止 | 检查服务器状态和防火墙设置 |
数据截断 | 缓冲区大小不足 | 增加缓冲区或分块传输 |
进阶主题[编辑 | 编辑源代码]
- 多路复用(select/poll/epoll)
- 非阻塞I/O
- SSL/TLS加密通信
- IPv6编程(
AF_INET6
)
通过掌握这些基础知识,您已经具备了开发简单网络应用的能力。实际项目中还需考虑错误处理、性能优化和安全性等问题。