在C语言中,网络编程是一个复杂且关键的领域,它涉及到多个方面的知识和技术,以下是对C语言网络类的详细介绍:
1、套接字(Socket):是网络通信的基础,用于实现不同主机之间的数据传输,在C语言中,通常使用socket()
函数来创建套接字,其原型为int socket(int domain, int type, int protocol)
。domain
指定协议族,如AF_INET
表示IPv4;type
指定套接字类型,如SOCK_STREAM
表示流式套接字(TCP),SOCK_DGRAM
表示数据报套接字(UDP);protocol
通常设置为0。
2、IP地址和端口号:IP地址用于标识网络上的设备,在C语言网络编程中,常使用struct sockaddr_in
结构体来存储IP地址和端口号信息,通过sin_family
字段指定地址族为AF_INET
,sin_port
字段指定端口号,sin_addr.s_addr
字段指定IP地址,可以使用inet_pton()
函数将点分十进制格式的IP地址字符串转换为网络字节序的二进制值进行存储。
1、创建套接字:调用socket()
函数创建一个套接字,如创建一个IPv4的TCP套接字可写成int sockfd = socket(AF_INET, SOCK_STREAM, 0);
,若创建失败,会返回-1并设置相应的errno错误码。
2、绑定地址:使用bind()
函数将套接字与本地的一个IP地址和端口号绑定起来,以便服务器能够监听该地址和端口上的客户端连接请求。bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
,其中serv_addr
是已设置好IP地址和端口号的struct sockaddr_in
结构体变量。
3、监听连接:对于TCP服务器,在绑定地址后需要调用listen()
函数来监听客户端的连接请求。listen(sockfd, 5);
表示允许最多5个客户端连接请求等待处理。
4、接受连接:当有客户端发起连接时,服务器调用accept()
函数接受连接,并返回一个新的套接字描述符用于与该客户端进行通信。int connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
,其中cli_addr
用于获取客户端的地址信息。
5、发送和接收数据:使用send()
和recv()
函数在服务器和客户端之间发送和接收数据。send(connfd, buffer, strlen(buffer), 0);
用于发送数据,recv(connfd, buffer, sizeof(buffer), 0);
用于接收数据。
6、关闭套接字:在通信结束后,需要使用close()
函数关闭套接字以释放资源,先关闭与客户端通信的套接字close(connfd);
,再关闭监听套接字close(sockfd);
。
1、创建套接字:与服务器端类似,客户端也需要创建一个套接字,但通常不需要绑定特定的端口号,系统会自动分配一个临时端口号。int sockfd = socket(AF_INET, SOCK_STREAM, 0);
。
2、连接到服务器:使用connect()
函数连接到服务器的指定IP地址和端口号。connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
。
3、发送和接收数据:同服务器端的发送和接收数据方式相同,使用send()
和recv()
函数进行数据的传输。
4、关闭套接字:通信结束后,调用close(sockfd);
关闭套接字。
1、头文件:进行网络编程时,需要包含一些常用的头文件,如<sys/types.h>
、<sys/socket.h>
、<netinet/in.h>
、<arpa/inet.h>
、<unistd.h>
等,这些头文件提供了网络编程所需的各种函数和数据结构的定义。
2、函数归纳:除了上述提到的socket()
、bind()
、listen()
、accept()
、connect()
、send()
、recv()
和close()
等函数外,还有一些其他常用的函数,如inet_pton()
用于将点分十进制格式的IP地址转换为网络字节序的二进制值;htons()
和ntohs()
分别用于将主机字节序的端口号转换为网络字节序和将网络字节序的端口号转换为主机字节序。
以下是一个简化的TCP服务器端和客户端的示例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define PORT 8888 #define BUFFER_SIZE 1024 int main() { int sockfd, connfd; struct sockaddr_in serv_addr, cli_addr; socklen_t clilen; char buffer[BUFFER_SIZE]; // 创建套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("Socket creation failed"); exit(EXIT_FAILURE); } // 绑定地址 serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("Bind failed"); close(sockfd); exit(EXIT_FAILURE); } // 监听连接 if (listen(sockfd, 5) < 0) { perror("Listen failed"); close(sockfd); exit(EXIT_FAILURE); } printf("Server is listening on port %d... ", PORT); // 接受连接并通信 while (1) { clilen = sizeof(cli_addr); connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); if (connfd < 0) { perror("Accept failed"); continue; } printf("Client connected... "); // 接收客户端数据 ssize_t bytes_received = recv(connfd, buffer, BUFFER_SIZE 1, 0); if (bytes_received < 0) { perror("Receive failed"); } else { buffer[bytes_received] = '