引言
C语言作为一门历史悠久且功能强大的编程语言,在网络编程领域有着广泛的应用。socket编程是C语言网络编程的核心技术之一,它允许程序员在网络中进行数据的传输和通信。本文将带领读者从入门到精通,通过实战案例解析,轻松掌握C语言socket编程的核心知识。
第一章:C语言socket编程基础
1.1 什么是socket
Socket是网络通信中的一种抽象层,它允许应用程序通过网络进行数据交换。在C语言中,socket编程主要使用socket()、bind()、listen()、accept()、connect()、send()、recv()等函数。
1.2 socket编程模型
C语言socket编程主要采用两种模型:阻塞IO和非阻塞IO。
- 阻塞IO:在数据传输过程中,如果数据没有准备好,程序会阻塞等待。
- 非阻塞IO:在数据传输过程中,如果数据没有准备好,程序不会阻塞,而是立即返回。
1.3 socket编程步骤
- 创建socket:使用
socket()函数创建一个socket。 - 绑定地址:使用
bind()函数将socket绑定到一个地址上。 - 监听连接:使用
listen()函数监听连接请求。 - 接受连接:使用
accept()函数接受连接请求。 - 发送数据:使用
send()函数发送数据。 - 接收数据:使用
recv()函数接收数据。 - 关闭socket:使用
close()函数关闭socket。
第二章:C语言socket编程实战案例
2.1 客户端-服务器模型
客户端-服务器模型是网络编程中最常见的模型之一。以下是一个简单的客户端-服务器模型示例:
// 服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制绑定到端口8080
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(8080);
// 绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 发送数据
char buffer[1024] = "Hello from server";
send(new_socket, buffer, strlen(buffer), 0);
close(new_socket);
return 0;
}
// 客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
struct sockaddr_in address;
int sock = 0, valread;
struct sockaddr_in serv_addr;
char buffer[1024] = "Hello from client";
// 创建socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
// 获取服务器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;
}
// 接收数据
valread = read( sock , buffer, 1024);
printf("%s\n", buffer);
close(sock);
return 0;
}
2.2 TCP客户端-服务器模型
TCP客户端-服务器模型是建立在TCP协议基础上的,它提供了可靠的数据传输。以下是一个简单的TCP客户端-服务器模型示例:
// 服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制绑定到端口8080
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(8080);
// 绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 发送数据
char buffer[1024] = "Hello from server";
send(new_socket, buffer, strlen(buffer), 0);
close(new_socket);
return 0;
}
// 客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
struct sockaddr_in address;
int sock = 0, valread;
struct sockaddr_in serv_addr;
char buffer[1024] = "Hello from client";
// 创建socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
// 获取服务器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;
}
// 接收数据
valread = read( sock , buffer, 1024);
printf("%s\n", buffer);
close(sock);
return 0;
}
2.3 UDP客户端-服务器模型
UDP客户端-服务器模型是建立在UDP协议基础上的,它提供了高效的数据传输。以下是一个简单的UDP客户端-服务器模型示例:
// 服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制绑定到端口8080
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(8080);
// 绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 接收数据
char buffer[1024] = "Hello from server";
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
recvfrom(server_fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_addr_len);
printf("Received from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
close(server_fd);
return 0;
}
// 客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
struct sockaddr_in address;
int sock = 0, valread;
struct sockaddr_in serv_addr;
char buffer[1024] = "Hello from client";
// 创建socket
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
// 获取服务器IP地址
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// 发送数据
sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
close(sock);
return 0;
}
第三章:C语言socket编程进阶
3.1 多线程socket编程
多线程socket编程可以提高程序的并发性能。以下是一个简单的多线程socket服务器示例:
// 服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
void *handle_client(void *socket_desc) {
int sock = *(int*)socket_desc;
char buffer[1024] = "Hello from server";
send(sock, buffer, strlen(buffer), 0);
close(sock);
free(socket_desc);
return 0;
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
pthread_t thread_id;
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制绑定到端口8080
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(8080);
// 绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 创建线程处理客户端请求
if (pthread_create(&thread_id, NULL, handle_client, (void*)&new_socket) < 0) {
perror("could not create thread");
return 1;
}
// 等待线程结束
pthread_join(thread_id, NULL);
close(server_fd);
return 0;
}
3.2 多进程socket编程
多进程socket编程可以提高程序的并发性能。以下是一个简单的多进程socket服务器示例:
// 服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/wait.h>
void handle_client(int sock) {
char buffer[1024] = "Hello from server";
send(sock, buffer, strlen(buffer), 0);
close(sock);
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制绑定到端口8080
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(8080);
// 绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 创建子进程处理客户端请求
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程
handle_client(new_socket);
exit(EXIT_SUCCESS);
} else {
// 父进程
close(new_socket);
wait(NULL);
}
close(server_fd);
return 0;
}
第四章:C语言socket编程总结
C语言socket编程是网络编程的核心技术之一,它为程序员提供了强大的网络通信能力。通过本文的介绍,读者应该已经掌握了C语言socket编程的基本知识和实战案例。在实际应用中,可以根据具体需求选择合适的socket编程模型和编程方式,提高网络通信的效率和可靠性。
第五章:C语言socket编程资源推荐
以下是一些C语言socket编程的资源推荐:
- 《C网络编程》
- 《UNIX网络编程》
- 《Linux网络编程》
- 《C语言网络编程实战》
- C语言socket编程相关的在线教程和博客
希望本文对读者有所帮助,祝您在C语言socket编程领域取得更好的成绩!
