• 近期的一些小总结(关于TCP/IP协议相关的)


    1、基本概念

    首先还是记录一下是什么,这个是关于通信的,本地进行消息传递的方式有很多,例如管道,消息队列,共享内存等,都是比较经典的进程间通信的方式,但这都是一个设备之间的进程进行通信,要实现设备和设备之间的通信需要使用Socket来实现。

    Socket将网络通信的三元组(ip地址,协议,端口)进行封装,使得进行网络中的进程间通信变得很方便。Socket的通信数据传输方式有两种比较常用的,分别是SOCK_STREAM和SOCK_DGRAM,前面一种是面向连接的数据传输方式,对数据的可靠性要求较高,类似MQTT协议中需要服务质量为1(QOS=1)的情况,第二种则是一种无连接的数据传输方式,设备只会发送数据不做数据校验,不会去管接收方有没有收到数据。(但是这样同样也提高了数据传输的效率

    2、建立连接的过程

    Socket是基于TCP/IP协议的,这里的TCP/IP是指[TCP(传输控制协议)和IP(网际协议)],可以直接理解为一套网络通信的标准协议格式。对于SOCKET开发者,TCP创建过程和连接拆除过程是由TCP/IP协议栈自动创建的。因此开发者并不需要控制这个过程。

    但是可以稍微有一个概念性的了解,例如下面的TCP建立连接时候的三次握手和断开连接的四次挥手:

    三次挥手

    理解为:

    • A->B:想与B建立连接
    • B->A:同意建立连接
    • A->B:收到

    之后就是AB之间进行数据的收发了,连接已经建立好了。

    四次握手

    理解为:

    • A->B:想断开连接
    • B->A:等待处理一下
    • B->A:好了,可以断开连接
    • A->B:收到

    之后就是断开连接,关闭Socket不在进行互相通信了。

    3、Socket常用接口

    Socket常用接口可以表示为下图所示:(下面的两种分别对应上述的两种常见的Socket接口

    TCP_Socket:
    在这里插入图片描述
    UDP_Socket
    在这里插入图片描述

    4、示例程序

    上述过程的示例程序可以表现为:

    tcp_server.c

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
     
    #define PORT 12345		//端口号
    #define BACKLOG 5	//最大监听数
     
    int main()
    {
    	int iSocketFD = 0;  //socket句柄
    	int iRecvLen = 0;   //接收成功后的返回值
    	int new_fd = 0; 	//建立连接后的句柄
    	char buf[4096] = {0}; //
    	struct sockaddr_in stLocalAddr = {0}; //本地地址信息结构图,下面有具体的属性赋值
    	struct sockaddr_in stRemoteAddr = {0}; //对方地址信息
    	socklen_t socklen = 0;  	
     
    	iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
    	if(0 > iSocketFD)
    	{
    		printf("创建socket失败!\n");
    		return 0;
    	}	
     
    	stLocalAddr.sin_family = AF_INET;  /*该属性表示接收本机或其他机器传输*/
    	stLocalAddr.sin_port = htons(PORT); /*端口号*/
    	stLocalAddr.sin_addr.s_addr=htonl("192.168.109.129"); /*IP,括号内容表示本机IP*/
     
    	//绑定地址结构体和socket
    	if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
    	{
    		printf("绑定失败!\n");
    		return 0;
    	}
     
    	//开启监听 ,第二个参数是最大监听数
    	if(0 > listen(iSocketFD, BACKLOG))
    	{
    		printf("监听失败!\n");
    		return 0;
    	}
     
    	printf("iSocketFD: %d\n", iSocketFD);	
    	//在这里阻塞知道接收到消息,参数分别是socket句柄,接收到的地址信息以及大小 
    	new_fd = accept(iSocketFD, (void *)&stRemoteAddr, &socklen);
    	if(0 > new_fd)
    	{
    		printf("接收失败!\n");
    		return 0;
    	}else{
    		printf("接收成功!\n");
    		//发送内容,参数分别是连接句柄,内容,大小,其他信息(设为0即可) 
    		send(new_fd, "这是服务器接收成功后发回的信息!", sizeof("这是服务器接收成功后发回的信息!"), 0);
    	}
     
    	printf("new_fd: %d\n", new_fd);	
    	iRecvLen = recv(new_fd, buf, sizeof(buf), 0);	
    	if(0 >= iRecvLen)    //对端关闭连接 返回0
    	{	
    		printf("接收失败或者对端关闭连接!\n");
    	}else{
    		printf("buf: %s\n", buf);
    	}
     
    	close(new_fd);
    	close(iSocketFD);
     
    	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

    tcp_client.c

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define PORT 12345			   //目标地址端口号
    #define ADDR "192.168.109.129" //目标地址IP
    
    int main()
    {
    	int iSocketFD = 0; // socket句柄
    	unsigned int iRemoteAddr = 0;
    	struct sockaddr_in stRemoteAddr = {0}; //对端,即目标地址信息
    	socklen_t socklen = 0;
    	char buf[4096] = {0}; //存储接收到的数据
    
    	iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
    	if (0 > iSocketFD)
    	{
    		printf("创建socket失败!\n");
    		return 0;
    	}
    	stRemoteAddr.sin_family = AF_INET;
    	stRemoteAddr.sin_port = htons(PORT);
    	inet_pton(AF_INET, ADDR, &iRemoteAddr);
    	stRemoteAddr.sin_addr.s_addr = iRemoteAddr;
    	//连接方法: 传入句柄,目标地址,和大小
    	if (0 > connect(iSocketFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
    	{
    		printf("连接失败!\n");
    	}
    	else
    	{
    		printf("连接成功!\n");
    		recv(iSocketFD, buf, sizeof(buf), 0); //将接收数据打入buf,参数分别是句柄,储存处,最大长度,其他信息(设为0即可)。
    		printf("Received:%s\n", buf);
    	}
    	close(iSocketFD); //关闭socket
    	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

    如果建立一个UDP连接的话:

    udp_client.c

    #include
    #include
    #include
    #include
    #include
     
    int main()
    {
         //创建socket对象
         int sockfd=socket(AF_INET,SOCK_DGRAM,0);
     
         //创建网络通信对象
         struct sockaddr_in addr;
         addr.sin_family =AF_INET;
         addr.sin_port =htons(1324);
         addr.sin_addr.s_addr = inet_addr("192.168.109.129"); //IP根据server所在主机的IP设定,这里是运行在同一PC端 
     
         while(1)
         {
             printf("input:");
             char buf[50];
             char buf1 = 0;
             scanf("%s",&buf);
             sendto(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&addr,sizeof(addr));
     
             socklen_t len=sizeof(addr);
             recvfrom(sockfd,&buf1,sizeof(buf1),0,(struct sockaddr*)&addr,&len);
     
             if(11 ==buf1)
             {
                printf(" server 成功接受\n");
             }
             else
             {
                 printf("server 数据丢失\n");
             }
     
         }
         close(sockfd); 
    }
    
    • 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

    udp_server.c

    #include
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
        //创建socket对象
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    
        //创建网络通信对象
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(1324);
        addr.sin_addr.s_addr = inet_addr("192.168.109.129");
    
        //绑定socket对象与通信链接
        int ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
        if (0 > ret)
        {
            printf("bind\n");
            return -1;
        }
        struct sockaddr_in cli;
        socklen_t len = sizeof(cli);
    
        while (1)
        {
            char buf[50];
            char buf1;
            recvfrom(sockfd, &buf, sizeof(buf), 0, (struct sockaddr *)&cli, &len);
            printf("recv num =%s\n", buf);
    
            buf1 = 11;
            sendto(sockfd, &buf1, sizeof(buf1), 0, (struct sockaddr *)&cli, len);
        }
        close(sockfd);
    }
    
    • 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

    使用的makefile

    SOURCE = $(wildcard *.c)
    TARGETS = $(patsubst %.c, %, $(SOURCE))
    
    CC = gcc
    CFLAGS = -Wall -g -lm#如果有math.h要加上这个lm选项
    
    all:$(TARGETS)
    
    $(TARGETS):%:%.c
    		$(CC) $< $(CFLAGS) -o $@
    
    .PHONY:clean all
    clean:
    	-rm -rf $(TARGETS)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    参考:
    https://www.jianshu.com/p/066d99da7cbd
    https://www.cnblogs.com/hissia/p/5730135.html
    https://blog.csdn.net/lzl980111/article/details/106188393

  • 相关阅读:
    深度学习经典网络 -- Inception系列(稀疏结构)
    Oracle数据库:oracle启动,oracle客户端工具plsql安装教程和使用方法
    518. 零钱兑换 II -- 完全背包
    大数据技术大全
    JNI查漏补缺(3)JNI调用java层
    (免费分享)基于springboot理财系统
    mac 备忘录
    基于STM32G431嵌入式学习笔记——六、串口中断实例(基于第12届蓝桥杯串口部分题目)
    JS 中防抖函数形成闭包的相关处理及思考
    回环设备(/dev/loop*)与losetup命令
  • 原文地址:https://blog.csdn.net/m0_51220742/article/details/126711517