当前位置:   article > 正文

Linux&C语言简单实现TCP客户端和服务器通信recv/ send-网络编程_linux下c语言can报文收发

linux下c语言can报文收发

TCP客户端和服务器通信

  • 基于C语言实现,TCP练习——用recv( )/ send( )
  • 命令行输入指定IP、端口
    -在这里插入图片描述

流程

  1. 服务器:
    1.创建流式套接字 socket
    2.填充服务器的网络信息结构体
    3.将网络信息结构体和套接字进行绑定 bind
    4.将套接字设置成被动监听状态 listen
    5.阻塞等待客户端连接 accept
    6.收发数据 read/write
    7.关闭套接字 close

  2. 客户端:
    1.创建流式套接字 socket
    2.填充服务器的网络信息结构体
    3.与服务器建立连接 connect
    4.收发数据 read/write
    5.关闭套接字 close

字节序转换函数

  1. 主机字节序到网络字节序

h host 主机
n net 网络

将无符号4字节整型  从主机-->网络
uint32_t htonl(uint32_t hostlong);
  • 1
  • 2
将无符号2字节整型  从主机-->网络 
 uint16_t htons(uint16_t hostshort);
  • 1
  • 2
  1. 网络字节序到主机字节序
将无符号4字节整型  从网络-->主机 
uint32_t ntohl(uint32_t netlong);
  • 1
  • 2
将无符号2字节整型  网络-->主机 
uint16_t ntohs(uint16_t netshort);
  • 1
  • 2

IP地址转换的函数:

  1. inet_addr()
将strptr所指的字符串转换成32位的网络字节序二进制值。
in_addr_t inet_addr(const char*strptr);
  • 1
  • 2
  1. inet_ntoa()
32位网络字节序二进制地址转换成点分十进制的字符串。
 char *inet_ntoa(stuct in_addr inaddr);
  • 1
  • 2

将套接字和网络信息结构体绑定bind

  1. 网络信息结构体 sockaddr
struct sockaddr {
	sa_family_t sa_family;
	char        sa_data[14];
}
只用于强制类型转换,防止编译器警告
  • 1
  • 2
  • 3
  • 4
  • 5
  1. sockaddr_in / in_addr
struct sockaddr_in {
	sa_family_t    sin_family; 		/* AF_INET */
	in_port_t      sin_port;   		/* 网络字节序的端口号 */
	struct in_addr sin_addr;  		/* IP地址 */ 		
 }; 		
  • 1
  • 2
  • 3
  • 4
  • 5
struct in_addr {
	uint32_t       s_addr;    		/* 网络字节序的IP地址 */
};
  • 1
  • 2
  • 3

代码实现

01server.c

#include <stdio.h>

/*socket-bind-listen-accept*/
#include <sys/types.h>
#include <sys/socket.h>
/*memset*/
#include <string.h>
/*sockaddr_in结构体*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
/*htons*/
#include <arpa/inet.h>
/*inet_addr*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*close*/
#include <unistd.h>
/*exit*/
#include <stdlib.h>
int main(int argc, char const *argv[])
{
    if (3 != argc)
    {
        printf("Use: %s <IP> <PORT>\n", argv[0]);
        exit(-1);
    }

    // 1.创建流式套接字
    // socket返回的文件描述符
    int sockfd = 0; // IPV4使用,//TCP
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket error");
        exit(-1);
    }

    // 2.填充服务器的网络信息结构体
    struct sockaddr_in addr;
    //清空、填充0
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET; // IPV4
    //端口号  //将无符号2字节整型  主机-->网络
    addr.sin_port = htons(atoi(argv[2]));
    // ip地址 //将strptr所指的字符串转换成32位的网络字节序二进制值。
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    //结构体长度
    socklen_t addr_len = sizeof(addr);

    // 3.将网络信息结构体和套接字进行绑定 bind
    //强制类型转换
    if (bind(sockfd, (struct sockaddr *)&addr, addr_len) == -1)
    {
        perror("connect error");
        exit(-1);
    }

    // 4.将套接字设置成被动监听状态 listen
    if (-1 == listen(sockfd, 5))
    {
        perror("listen error");
        exit(-1);
    }

    // 5.阻塞等待客户端连接 accept 有客户端连接就会解除阻塞
    //返回一个新的文件描述符,专门用于和该客户端通信
    int accept_fd = 0;

    //用来保存客户端信息的结构体
    struct sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(client_addr));
    socklen_t client_addr_len = sizeof(client_addr);

    printf("等待客户端\n");
    if ((accept_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len)) == -1)
    {
        perror("accept error");
        exit(-1);
    }
    //inet_ntoa()将32位网络字节序二进制地址转换成点分十进制的字符串。
    将无符号2字节整型  网络-->主机 uint16_t ntohs(uint16_t netshort);
    printf("客户端[%s]-[%d]连接成功\n",
           inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    while (1)
    {
        char buf[128] = {0};
        //收
        printf("客户端 >  ");
        fflush(stdout);
        recv(accept_fd, buf, 128, 0);
        printf("%s\n", buf);
        if (strcmp(buf, "quit") == 0)
        {
            //关闭文件描述符
            close(sockfd);
            close(accept_fd);
            break;
        }

        //发
        printf("input  > ");
        memset(buf, 0, sizeof(buf));
        scanf("%s", buf);
        send(accept_fd, buf, 128, 0);
        if (strcmp(buf, "quit") == 0) // break;
        {
            //关闭文件描述符
            close(sockfd);
            close(accept_fd);
            break;
        }
    }

    //关闭文件描述符
    close(sockfd);
    close(accept_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
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121

02client.c

#include <stdio.h>

/*socket-bind-listen-accept*/
#include <sys/types.h>
#include <sys/socket.h>
/*memset*/
#include <string.h>
/*sockaddr_in结构体*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
/*htons*/
#include <arpa/inet.h>
/*inet_addr*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*close*/
#include <unistd.h>
/*exit*/
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    if (3!=argc)
    {
        printf("Use: %s <IP> <PORT>",argv[0]);
        exit(-1);
    }
    // 1.创建流式套接字
    // socket返回的文件描述符
    int sockfd = 0; // IPV4使用,//TCP
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket error");
        exit(-1);
    }

    // 2.填充服务器的网络信息结构体
    struct sockaddr_in addr;
    //清空、填充0
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET; // IPV4
    //端口号  //将无符号2字节整型  主机-->网络
    addr.sin_port = htons(atoi(argv[2]));
    // ip地址 //将strptr所指的字符串转换成32位的网络字节序二进制值。
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    //结构体长度
    socklen_t addr_len = sizeof(addr);

    //3.与服务器建立连接 connect
                              //强制类型转换
    if(-1 == connect(sockfd, (struct sockaddr *)&addr, addr_len)){
		perror("connect error");
		exit(-1);
	}
    while (1)
    {
        char bu[128] = {0};
        //发
        printf("input  > ");
        scanf("%s", bu);
        send(sockfd, bu, 128,0);
        if (strcmp(bu,"quit")==0)
        {
            //关闭文件描述符
            close(sockfd);
            break;
        }

        //收
        memset(bu, 0, sizeof(bu));
        printf("服务器 > ");
        fflush(stdout);
	    recv(sockfd, bu, 128,0);
        printf("%s\n", bu);
        if (strcmp(bu,"quit")==0)
        {
            //关闭文件描述符
            close(sockfd);
            break;
        }
    
    }
    
   
    //关闭文件描述符
    close(sockfd);
   
    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
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

执行结果

在这里插入图片描述

6. 非原创

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/144111
推荐阅读
相关标签
  

闽ICP备14008679号