当前位置:首页 > 行业动态 > 正文

c 网络编程

网络编程是利用计算机网络进行数据传输和通信的编程技术,涉及客户端与服务器间的连接、数据交换等操作,旨在实现远程访问、资源共享等功能。

C 语言网络编程是利用 C 语言进行网络应用程序开发的过程,它主要依赖于套接字(Socket)编程接口来实现网络通信,以下是关于 C 语言网络编程的详细内容:

一、基础概念与准备工作

1、网络协议:网络编程基于网络协议,如 TCP/IP 协议族,TCP 提供可靠的、面向连接的传输服务,适用于需要高可靠性的应用;UDP 则提供无连接的服务,数据传输速度较快但不如 TCP 可靠。

2、套接字:套接字是网络编程的核心,它是操作系统提供的一种网络通信接口,通过套接字,程序可以在网络中发送和接收数据,套接字分为流套接字(用于 TCP 连接)和数据报套接字(用于 UDP 通信)。

二、套接字编程步骤

1、创建套接字:使用socket() 函数创建一个套接字,该函数返回一个套接字描述符,如果失败则返回 -1。

   int sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0) {
       perror("socket creation failed");
       exit(EXIT_FAILURE);
   }

2、绑定套接字:对于服务器端程序,需要将套接字绑定到一个特定的 IP 地址和端口号上,使用bind() 函数实现,这一步对客户端程序通常不是必须的。

   struct sockaddr_in serv_addr;
   serv_addr.sin_family = AF_INET;
   serv_addr.sin_port = htons(PORT);
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
       perror("socket bind failed");
       exit(EXIT_FAILURE);
   }

3、监听和接受连接:服务器端需要监听端口,等待客户端的连接请求,并使用accept() 函数接受连接。listen() 函数使套接字进入被动打开状态,准备接受连接。

   if (listen(sockfd, 5) < 0) {
       perror("Listen failed");
       exit(EXIT_FAILURE);
   }
   int new_socket = accept(sockfd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
   if (new_socket < 0) {
       perror("Accept failed");
       exit(EXIT_FAILURE);
   }

4、发送和接收数据:无论是客户端还是服务器端,都需要使用send()recv() 函数来发送和接收数据。

   char buffer[1024] = {0};
   read(new_socket, buffer, 1024);
   printf("%s
", buffer);
   char *message = "Hello from server";
   send(new_socket, message, strlen(message), 0);

5、关闭套接字:通信结束后,应关闭套接字以释放资源,使用close() 函数。

   close(new_socket);
   close(sockfd);

三、实际案例分析

以下是一个简单的 TCP 服务器和客户端的例子:

1、TCP 服务器

   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <unistd.h>
   #include <arpa/inet.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #define PORT 8080
   int main() {
       int server_fd, new_socket;
       struct sockaddr_in address;
       int opt = 1;
       int addrlen = sizeof(address);
       char buffer[1024] = {0};
       char *message = "Hello from server";
       // Creating socket file descriptor
       if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
           perror("socket failed");
           exit(EXIT_FAILURE);
       }
       // Forcefully attaching socket to the port 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(PORT);
       // Bind the socket to the address and port number specified in address structure
       if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
           perror("bind failed");
           exit(EXIT_FAILURE);
       }
       // Start listening for client connections. Here, the backlog queue is set to 3
       if (listen(server_fd, 3) < 0) {
           perror("listen");
           exit(EXIT_FAILURE);
       }
       // Accept a connection from a client
       if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
           perror("accept");
           exit(EXIT_FAILURE);
       }
       // Read data sent by the client from the socket into the buffer array and print it on the console
       read(new_socket, buffer, 1024);
       printf("%s
",buffer );
       // Send a response back to the client using the same socket that was used to receive the data from the client
       send(new_socket, message, strlen(message), 0);
       printf("Hello message sent
");
       return 0;
   }

2、TCP 客户端

   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <unistd.h>
   #include <arpa/inet.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #define PORT 8080
   int main() {
       struct sockaddr_in address;
       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("
 Socket creation error 
");
           return -1;
       }
       memset(&serv_addr, '0', sizeof(serv_addr));
       serv_addr.sin_family = AF_INET;
       serv_addr.sin_port = htons(PORT);
       // Convert IPv4 and IPv6 addresses from text to binary form
       if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
           printf("
Invalid address/ Address not supported 
");
           return -1;
       }
       if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
           printf("
Connection Failed 
");
           return -1;
       }
       send(sock, hello, strlen(hello), 0);
       printf("Hello message sent
");
       int valread = read(sock, buffer, 1024);
       printf("%s
",buffer );
       return 0;
   }

四、常见问题及解答

1、问题:为什么在调用socket() 函数时会失败?

回答:可能的原因包括指定的协议族不支持、系统资源不足等,请检查错误信息以确定具体原因。

2、问题:如何选择合适的协议和套接字类型?

回答:这取决于应用的需求,如果需要可靠的数据传输,应选择 TCP;如果需要快速但不可靠的传输,可以选择 UDP,根据传输的数据类型选择合适的套接字类型。