Socket编程详解:从基本概念到实例应用(TCP|UDP C语言实例详解)

马肤
这是懒羊羊

简介:

Socket编程是网络编程中至关重要的一部分,它提供了一种在不同主机之间进行数据通信的方式。本篇博客将详细介绍Socket编程的基本概念、原理和实例应用,帮助读者深入理解和掌握这一重要技术。

正文:

一、Socket编程概述

Socket是一种通信机制,通过它可以在不同主机之间进行数据交换。在Socket编程中,有两种常见的通信模式:客户端-服务器模式和点对点模式。它基于TCP/IP协议栈,并使用IP地址和端口号来标识通信的目标。

二、Socket编程基本步骤

Socket编程是一种用于实现网络通信的编程接口,可以通过TCP(传输控制协议)和UDP(用户数据报协议)实现不同类型的连接。下面将详细介绍TCP和UDP的开发流程,并详细介绍常用的Socket编程函数的原型和参数用法。

TCP开发流程:

  1. 服务器端:

    • 创建套接字:int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    • 绑定地址:struct sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons(port); serverAddress.sin_addr.s_addr = INADDR_ANY; bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
    • 监听连接:listen(serverSocket, backlog);
    • 接受连接:struct sockaddr_in clientAddress; int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, sizeof(clientAddress));
    • 发送和接收数据:send(clientSocket, buffer, size, 0); recv(clientSocket, buffer, size, 0);
    • 关闭连接:close(clientSocket); close(serverSocket);
    • 客户端:

      • 创建套接字:int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
      • 连接服务器:struct sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons(port); serverAddress.sin_addr.s_addr = inet_addr(serverIP); connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
      • 发送和接收数据:send(clientSocket, buffer, size, 0); recv(clientSocket, buffer, size, 0);
      • 关闭连接:close(clientSocket);

UDP开发流程:

  1. 服务器端:

    • 创建套接字:int serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
    • 绑定地址:struct sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons(port); serverAddress.sin_addr.s_addr = INADDR_ANY; bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
    • 接收和发送数据:recvfrom(serverSocket, buffer, size, 0, (struct sockaddr*)&clientAddress, sizeof(clientAddress)); sendto(serverSocket, buffer, size, 0, (struct sockaddr*)&clientAddress, sizeof(clientAddress));
    • 关闭套接字:close(serverSocket);
    • 客户端:

      • 创建套接字:int clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
      • 发送和接收数据:sendto(clientSocket, buffer, size, 0, (struct sockaddr*)&serverAddress, sizeof(serverAddress)); recvfrom(clientSocket, buffer, size, 0, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
      • 关闭套接字:close(clientSocket);

常用函数的原型和参数用法详解:

  1. socket()函数:
    • 原型:int socket(int domain, int type, int protocol);
    • 参数:
      • domain:地址族,通常为AF_INET(IPv4)或AF_INET6(IPv6)。
      • type:套接字类型,可以是SOCK_STREAM(TCP)或SOCK_DGRAM(UDP)。
      • protocol:协议,通常为0,表示自动选择合适的协议。

2

. bind()函数:

  • 原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:
    • sockfd:套接字描述符。
    • addr:指向本地地址结构体的指针。
    • addrlen:地址结构体的长度。
      1. listen()函数:

        • 原型:int listen(int sockfd, int backlog);
        • 参数:
          • sockfd:套接字描述符。
          • backlog:待连接队列的最大长度。
          • accept()函数:

            • 原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
            • 参数:
              • sockfd:套接字描述符。
              • addr:指向客户端地址结构体的指针,用于存储客户端的地址信息。
              • addrlen:指向地址结构体长度的指针。
              • connect()函数:

                • 原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
                • 参数:
                  • sockfd:套接字描述符。
                  • addr:指向目标地址结构体的指针。
                  • addrlen:地址结构体的长度。
                  • send()函数:

                    • 原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
                    • 参数:
                      • sockfd:套接字描述符。
                      • buf:指向要发送数据的缓冲区的指针。
                      • len:要发送的数据的长度。
                      • flags:发送标志,通常为0。
                      • recv()函数:

                        • 原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
                        • 参数:
                          • sockfd:套接字描述符。
                          • buf:指向接收数据的缓冲区的指针。
                          • len:要接收的数据的最大长度。
                          • flags:接收标志,通常为0。
                          • sendto()函数:

                            • 原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
                            • 参数:
                              • sockfd:套接字描述符。
                              • buf:指向要发送数据的缓冲区的指针。
                              • len:要发送的数据的长度。
                              • flags:发送标志,通常为0。
                              • dest_addr:指向目标地址结构体的指针。
                              • addrlen:目标地址结构体的长度。
                              • recvfrom()函数:

                                • 原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
                                • 参数:
                                  • sockfd:套接字描述符。
                                  • buf:指向接收数据的缓冲区的指针。
                                  • len:要接收的数据的最大长度。
                                  • flags:接收标志,通常为0。
                                  • src_addr:指向源地址结构体的指针,用于存储源地址信息。
                                  • addrlen:指向地址结构体长度的指针。
                                  • close()函数:

      原型:int close(int sockfd);

      - 参数:套接字描述符。

      通过使用这些函数,可以实现TCP和UDP通信的服务器端和客户端程序。TCP提供可靠的、面向连接的通信,适用于需要确保数据可靠性和顺序性的场景,而UDP提供无连接的通信,适用于实时性要求较高但可靠性要求较低的场景。

      三、Socket编程实例

      以下是使用C语言通过Socket实现TCP和UDP通信的服务端和客户端通信程序的示例:

      TCP通信示例:

      服务端(server.c):

      #include 
      #include 
      #include 
      #include 
      #include 
      #define SERVER_IP "127.0.0.1"
      #define SERVER_PORT 8080
      #define BUFFER_SIZE 1024
      int main() {
          int serverSocket, clientSocket;
          struct sockaddr_in serverAddr, clientAddr;
          socklen_t clientAddrLen;
          char buffer[BUFFER_SIZE];
          // 创建服务端套接字
          serverSocket = socket(AF_INET, SOCK_STREAM, 0);
          if (serverSocket == -1) {
              perror("Failed to create socket");
              exit(EXIT_FAILURE);
          }
          // 设置服务器地址信息
          memset(&serverAddr, 0, sizeof(serverAddr));
          serverAddr.sin_family = AF_INET;
          serverAddr.sin_port = htons(SERVER_PORT);
          serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
          // 绑定套接字到指定地址和端口
          if (bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) {
              perror("Failed to bind socket");
              exit(EXIT_FAILURE);
          }
          // 监听连接请求
          if (listen(serverSocket, 5) == -1) {
              perror("Failed to listen");
              exit(EXIT_FAILURE);
          }
          printf("Server listening on port %d...\n", SERVER_PORT);
          // 接受客户端连接
          clientAddrLen = sizeof(clientAddr);
          clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, &clientAddrLen);
          if (clientSocket == -1) {
              perror("Failed to accept client connection");
              exit(EXIT_FAILURE);
          }
          printf("Client connected: %s\n", inet_ntoa(clientAddr.sin_addr));
          // 接收数据
          memset(buffer, 0, sizeof(buffer));
          if (recv(clientSocket, buffer, BUFFER_SIZE, 0) == -1) {
              perror("Failed to receive data");
              exit(EXIT_FAILURE);
          }
          printf("Client message: %s\n", buffer);
          // 发送响应
          strcpy(buffer, "Hello, Client!");
          if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
              perror("Failed to send data");
              exit(EXIT_FAILURE);
          }
          // 关闭套接字
          close(clientSocket);
          close(serverSocket);
          return 0;
      }
      

      客户端(client.c):

      #include 
      #include 
      #include 
      #include 
      #include 
      #define SERVER_IP "127.0.0.1"
      #define SERVER_PORT 8080
      #define BUFFER_SIZE 1024
      int main() {
          int clientSocket;
          struct sockaddr_in serverAddr;
          char buffer[BUFFER_SIZE];
          // 创建客户端套接字
          clientSocket = socket(AF_INET, SOCK_STREAM, 0);
          if (clientSocket == -1) {
              perror("Failed to create socket");
              exit(EXIT_FAILURE);
          }
          // 设置服务器地址信息
          memset(&serverAddr, 0, sizeof(serverAddr));
          serverAddr.sin_family = AF_INET;
          serverAddr.sin_port = htons(SERVER_PORT);
          if (inet_pton(AF_INET, SERVER_IP, &(serverAddr.sin_addr)) 
              perror("Failed to set server IP");
              exit(EXIT_FAILURE);
          }
          // 连接到服务器
          if (connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) {
              perror("Failed to connect to server");
              exit(EXIT_FAILURE);
          }
          printf("Connected to server %s:%d\n", SERVER_IP, SERVER_PORT);
          // 发送数据
          strcpy(buffer, "Hello, Server!");
          if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
              perror("Failed to send data");
              exit(EXIT_FAILURE);
          }
          // 接收响应
          memset(buffer, 0, sizeof(buffer));
          if (recv(clientSocket, buffer, BUFFER_SIZE, 0) == -1) {
              perror("Failed to receive data");
              exit(EXIT_FAILURE);
          }
          printf("Server response: %s\n", buffer);
          // 关闭套接字
          close(clientSocket);
          return 0;
      }
      
          int serverSocket;
          struct sockaddr_in serverAddr, clientAddr;
          socklen_t clientAddrLen;
          char buffer[BUFFER_SIZE];
          // 创建服务端套接字
          serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
          if (serverSocket == -1) {
              perror("Failed to create socket");
              exit(EXIT_FAILURE);
          }
          // 设置服务器地址信息
          memset(&serverAddr, 0, sizeof(serverAddr));
          serverAddr.sin_family = AF_INET;
          serverAddr.sin_port = htons(SERVER_PORT);
          serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
          // 绑定套接字到指定地址和端口
          if (bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) {
              perror("Failed to bind socket");
              exit(EXIT_FAILURE);
          }
          printf("Server listening on port %d...\n", SERVER_PORT);
          // 接收数据
          clientAddrLen = sizeof(clientAddr);
          memset(buffer, 0, sizeof(buffer));
          if (recvfrom(serverSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&clientAddr, &clientAddrLen) == -1) {
              perror("Failed to receive data");
              exit(EXIT_FAILURE);
          }
          printf("Client message: %s\n", buffer);
          // 发送响应
          strcpy(buffer, "Hello, Client!");
          if (sendto(serverSocket, buffer, strlen(buffer), 0, (struct sockaddr *)&clientAddr, clientAddrLen) == -1) {
              perror("Failed to send data");
              exit(EXIT_FAILURE);
          }
          // 关闭套接字
          close(serverSocket);
          return 0;
      }
      
          int clientSocket;
          struct sockaddr_in serverAddr;
          char buffer[BUFFER_SIZE];
          // 创建客户端套接字
          clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
          if (clientSocket == -1) {
              perror("Failed to create socket");
              exit(EXIT_FAILURE);
          }
          // 设置服务器地址信息
          memset(&serverAddr, 0, sizeof(serverAddr));
          serverAddr.sin_family = AF_INET;
          serverAddr.sin_port = htons(SERVER_PORT);
          if (inet_pton(AF_INET, SERVER_IP, &(serverAddr.sin_addr)) 
              perror("Failed to set server IP");
              exit(EXIT_FAILURE);
          }
          printf("Connected to server %s:%d\n", SERVER_IP, SERVER_PORT);
          // 发送数据
          strcpy(buffer, "Hello, Server!");
          if (sendto(clientSocket, buffer, strlen(buffer), 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) {
              perror("Failed to send data");
              exit(EXIT_FAILURE);
          }
          // 接收响应
          memset(buffer, 0, sizeof(buffer));
          if (recvfrom(clientSocket, buffer, BUFFER_SIZE, 0, NULL, NULL) == -1) {
              perror("Failed to receive data");
              exit(EXIT_FAILURE);
          }
          printf("Server response: %s\n", buffer);
          // 关闭套接字
          close(clientSocket);
          return 0;
      }
      

文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复:表情:
评论列表 (暂无评论,0人围观)

还没有评论,来说两句吧...

目录[+]

取消
微信二维码
微信二维码
支付宝二维码