• 服务器搭建(TCP套接字)-基础版(客户端)


    在这里插入图片描述

    一、socket

    在这里插入图片描述

    1.1、vim man查看socket

    :!man socket
    
    • 1

    在这里插入图片描述
    在这里插入图片描述

    1.2、 依赖的头文件

     #include      
     #include 
    
    • 1
    • 2

    1.3、原型

    int socket(int domain, int type, int protocol);
    
    • 1
    domain说明
    AF_INETIPV4协议
    AF_INET6IPV6协议
    AF_LOCALUnix域协议
    type说明
    SOCK_STREAM字节流套接字(TCP/SCTP)
    SOCK_DGRAM数据报套接字(UDP)
    SOCK_RAM原始套接字 (IPv4/IPv6)
    SOCK_SEQPACKET有序分组套接字(SCTP)
    protocol说明
    IPPROTO_CPTCP传输协议
    IPPROTO_UDPUDP传输协议
    IPPROTO_SCTPSCTP传输协议

    socket函数在成功时会返回一个小的非负整数值,它与文件描述符类似,就称它为套接字描述符。只需要指定协议族(IPV4、IPV6或Unix)和套接字类型即可

    • 代码实现
    socket_fd=socket(AF_INET,SOCK_STREAM,0);
    
    • 1

    二、connect

    在这里插入图片描述

    2.1、原型

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    
    • 1

    connect() 函数用于在客户端应用程序中与服务器建立连接。需要注意的是,connect() 函数可能会阻塞,直到连接成功建立或发生错误。因此,您可以使用适当的超时机制或非阻塞 Socket 设置来控制连接过程的行为。

    入参:

    • sockfd:要连接的客户端 Socket 的文件描述符。
    • addr:指向服务器地址结构的指针,其中包含服务器的 IP 地址和端口号。
    • addrlen:服务器地址结构的长度。

    返回值:

    • 0 表示连接成功
    • 返回值为 -1 表示连接失败,并设置相应的错误代码(可以使用 perror() 函数打印错误信息)。

    2.2、代码

    #define SERVER_PORT 8596 
    #define MESSAGE_LENGTH 1024
    
    int ret = -1;
    int socket_fd;
    //server addr
    struct sockaddr_in serverAddr;
    
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    //inet_addr()函数,将点分十进制IP转换成网络字节序IP
    serverAddr.sin_addr.s_addr = inet_addr(args[1]);
    if(connect(socket_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0){
        perror("connect error");
        return 1;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    三、send

    在这里插入图片描述

    3.1、原型

    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    
    • 1

    send 是一个在网络编程中使用的函数,用于发送数据到已连接的套接字或发送数据报套接字中。

    入参:

    • sockfd:整型参数,表示要发送数据的套接字的文件描述符。
    • buf:指向要发送数据的缓冲区的指针。
    • len:无符号整型参数,表示要发送数据的长度。
    • flags:整型参数,用于指定发送操作的可选标志。常见的标志包括 0(无特殊标志)和 MSG_DONTWAIT(非阻塞模式发送)等。

    返回值

    • 如果成功发送数据,send 返回发送的字节数。
    • 如果连接关闭(对于流套接字)或发送超时(对于数据报套接字),send 返回 0。
    • 如果发生错误,send 返回 -1,并设置相应的错误码,可以通过 errno 全局变量获取具体的错误信息。

    3.2、源码

    #define MESSAGE_LENGTH 1024
    
    char sendbuf[MESSAGE_LENGTH];
    
     while(1)
      {
        memset(sendbuf, 0, MESSAGE_LENGTH);
    
        printf("send message:");
    
        fgets(sendbuf,MESSAGE_LENGTH,stdin);
        //printf("\n");
        ret = send(socket_fd, sendbuf, strlen(sendbuf), 0);
        if(ret <= 0 ){
          printf("the connection is disconnection!\n");
          break;
        }
    
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    四、recv

    在这里插入图片描述

    4.1、原型

    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    
    • 1

    recv 是一个在网络编程中使用的函数,用于接收数据从已连接的套接字或接收数据报套接字中。

    需要注意的是,recv 函数是一个阻塞调用,即在没有数据到达之前,它会一直等待。如果需要非阻塞的操作,可以使用非阻塞 I/O 或多线程/多进程的方式处理接收操作。

    入参:

    • sockfd:整型参数,表示要接收数据的套接字的文件描述符。
    • buf:指向接收数据缓冲区的指针,用于存储接收到的数据。
    • len:无符号整型参数,表示接收数据缓冲区的长度。
    • flags:整型参数,用于指定接收操作的可选标志。常见的标志包括 0(无特殊标志)、MSG_DONTWAIT(非阻塞模式接收)和 MSG_WAITALL(阻塞模式接收,直到接收到指定长度的数据)等。

    返回值:

    • 如果成功接收数据,recv 返回接收到的字节数。
    • 如果连接关闭(对于流套接字)或接收超时(对于数据报套接字),recv 返回 0。
    • 如果发生错误,recv 返回 -1,并设置相应的错误码,可以通过 errno 全局变量获取具体的错误信息。

    五、完整代码

    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define SERVER_PORT 8596 
    #define MESSAGE_LENGTH 1024
    
    int main(int argc,char* args[])
    {
    
      int ret = -1;
      int socket_fd;
    
      //server addr
      struct sockaddr_in serverAddr;
    
      char sendbuf[MESSAGE_LENGTH];
      char recvbuf[MESSAGE_LENGTH];
    
      int data_len;
    
      if((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
      {
        perror("socket");
        return 1;
      }
    
      serverAddr.sin_family = AF_INET;
      serverAddr.sin_port = htons(SERVER_PORT);
    
      //inet_addr()函数,将点分十进制IP转换成网络字节序IP
      serverAddr.sin_addr.s_addr = inet_addr(args[1]);
    
      if(connect(socket_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
      {
        perror("connect");
        return 1;
      }
    
      printf("success to connect server...\n");
    
      while(1)
      {
        memset(sendbuf, 0, MESSAGE_LENGTH);
    
        printf("send message:");
    
        fgets(sendbuf,MESSAGE_LENGTH,stdin);
        //printf("\n");
        ret = send(socket_fd, sendbuf, strlen(sendbuf), 0);
        if(ret <= 0 ){
          printf("the connection is disconnection!\n");
          break;
        }
    
        if(strcmp(sendbuf, "quit") == 0){
          break;
        }
    
        printf("receive message:");
    
        recvbuf[0] = '\0';
        data_len = recv(socket_fd, recvbuf, MESSAGE_LENGTH, 0);
    
        recvbuf[data_len] = '\0';
    
        printf("%s\n", recvbuf);
    
      }
    
      close(socket_fd);
    
      return 0;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    ps:大多数操作系统中,文件描述符 0、1 和 2 分别用于标准输入(stdin)、标准输出(stdout)和标准错误(stderr)。这些文件描述符通常会在程序启动时被打开,并且在整个程序的生命周期内都是打开的。
    因此,文件描述符的数值从 3 开始,是为了避免与标准输入、标准输出和标准错误的文件描述符冲突。这样,你可以将自己的文件描述符从 3 开始分配给其他打开的文件、套接字或其他输入/输出源。

  • 相关阅读:
    STM32CubeMX学习笔记3-串口通信2(不定长数据)
    数学建模常见四大赛题
    对比学习里面instance_loss的意义
    BGP选路规则
    关于响应式编程ReactiveX,RxGo
    unity中实现场景跳转
    教资笔记(目录)
    Sendable 和 @Sendable 闭包 —— 代码实例详解
    WebSocket 心跳机制如何实现
    重新定义分析 - EventBridge 实时事件分析平台发布
  • 原文地址:https://blog.csdn.net/u011557841/article/details/132908152