C语言网络编程基础
C语言在网络编程领域具有重要地位,其高效性和灵活性使其成为实现网络通信的常用语言,网络编程主要涉及套接字(Socket)的使用,通过套接字可以实现不同主机上的进程间通信。
套接字编程基础
1、创建套接字:使用socket()
函数创建一个套接字,该函数需要指定协议族、套接字类型和协议参数,创建一个TCP套接字的代码如下:
int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("Socket creation failed"); exit(EXIT_FAILURE); }
AF_INET
表示IPv4协议族,SOCK_STREAM
表示面向连接的流式套接字。
2、绑定地址:将套接字与本地的一个地址(IP地址和端口号)绑定起来,通常用于服务器端,使用bind()
函数实现,示例代码如下:
struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(PORT); if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("Bind failed"); close(sockfd); exit(EXIT_FAILURE); }
这里将套接字绑定到所有可用的接口上,并指定了端口号。
3、监听连接请求:对于TCP服务器,需要调用listen()
函数来监听客户端的连接请求。
if (listen(sockfd, 5) < 0) { perror("Listen failed"); close(sockfd); exit(EXIT_FAILURE); }
第二个参数指定了最大监听队列长度。
4、接受连接:当有客户端尝试连接服务器时,服务器使用accept()
函数接受连接,并创建一个新的套接字用于与客户端通信,示例代码如下:
struct sockaddr_in cli_addr; socklen_t clilen = sizeof(cli_addr); int connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); if (connfd < 0) { perror("Accept failed"); close(sockfd); exit(EXIT_FAILURE); }
5、发送和接收数据:建立连接后,可以使用send()
和recv()
函数进行数据的发送和接收。
char buffer[BUFFER_SIZE]; ssize_t bytes_sent = send(connfd, buffer, strlen(buffer), 0); if (bytes_sent < 0) { perror("Send failed"); close(connfd); exit(EXIT_FAILURE); } ssize_t bytes_received = recv(connfd, buffer, sizeof(buffer), 0); if (bytes_received < 0) { perror("Receive failed"); close(connfd); exit(EXIT_FAILURE); }
6、关闭套接字:当不再需要使用套接字时,应使用close()
函数及时关闭它,以释放资源。
close(connfd); close(sockfd);
网络协议相关知识
1、TCP协议:提供可靠的、有序的、无差错的数据传输服务,它适用于需要高可靠性的网络应用,如文件传输、电子邮件等,在TCP通信中,数据会被分成适当长度的报文段进行传输,并确保每个报文段都能正确到达接收方且按序排列。
2、UDP协议:一个简单的面向数据报的传输层协议,不提供可靠性保证,但传输速度较快,它适用于对实时性要求较高但对数据准确性要求相对较低的应用,如视频流、在线游戏等。
多线程编程在网络编程中的应用
在实际应用中,服务器通常需要处理多个客户端的连接请求,为了提高并发性能,可以使用多线程编程,在C语言中,可以使用pthread
库来创建和管理线程。
pthread_t thread_id; pthread_create(&thread_id, NULL, handle_client, (void *)&newsockfd); pthread_detach(thread_id);
这样可以为每个客户端连接创建一个新的线程来处理,提高服务器的响应能力。
示例代码:简单的TCP服务器和客户端
以下是一个简单的TCP服务器和客户端示例:
1、TCP服务器
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <pthread.h> #define PORT 8080 void *handle_client(void *arg) { int sockfd = *(int *)arg; char buffer[1024]; int n; while ((n = recv(sockfd, buffer, sizeof(buffer), 0)) > 0) { send(sockfd, buffer, n, 0); } close(sockfd); return NULL; } int main() { int server_fd, new_socket; struct sockaddr_in address; int addrlen = sizeof(address); if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket creation failed"); 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"); close(server_fd); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("Listen failed"); close(server_fd); exit(EXIT_FAILURE); } while (1) { if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { perror("Accept failed"); continue; } pthread_t thread_id; pthread_create(&thread_id, NULL, handle_client, (void *)&new_socket); pthread_detach(thread_id); } close(server_fd); return 0; }
2、TCP客户端
#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 *message = "Hello from client"; char buffer[1024] = {0}; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf(" Socket creation error "); return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { printf(" Invalid address "); return -1; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf(" Connection failed "); return -1; } send(sock, message, strlen(message), 0); printf("Hello message sent "); return 0; }