C语言复健记录二:TCP/IP协议簇

TCP/IP协议簇

进行网络编程时, 不可避免的会遇到通信协议的问题.
TCP/IP协议簇全称叫做 transmission control protocol/Internet protocol,即传输控制协议与以太网互联协议,所有的网络协议都是在这个协议簇中,包括 TCP协议,UDP协议,IP协议,IMCP协议,HTTP协议等. TCP/IP协议簇是网络通信最基本的标准.
TCP/IP协议簇一般分为四个层次,应用层,传输层,网络层和网络接口层.

应用层(application layer)

包含所有的高层协议,比如TELNET,FTP,SMTP,DNS,NNTP,HTTP,MQTT等, 应用层约定了具体的通信格式.

传输层(transport layer)

包含TCP协议和UDP协议,传输层的作用是将应用层封好的包按照包里的地址分发到下一层,TCP协议是面向连接的协议,而UDP则是面向无连接的协议.

网络层(internet layer)

常用的是IP协议,其作用是将封好地址的包在进行分组,然后发到下一层发送出去.

网络接口层(network interface layer)

网络通信中基础部分,负责收发ip层的数据包,是PC和网络的实际连接层.

应用层相当于处理信的内容,传输层负责信的地址,网络层则具体规划运输路线,网络接口层即物流周转中心.

在网络通信中,信变成了数据包,以TCP协议举例:

分层结构14 bytes20 bytes20 bytes4 bytes
应用层用户数据
传输层TCP首部用户数据
网络层IP首部TCP首部用户数据
网络接口层网络首部IP首部TCP首部用户数据以太网尾部

用户数据通过各个层级之后,封装成数据包,在网络中传输,当接收到数据包后,在通过层层解包,得到最后的用户数据.

通信协议

通信协议的作用范围比较模糊,有按功能划分也有按照过程划分.

TCP协议

TCP协议是作用在传输层上的面向连接的高可靠性的协议,TCP的报文格式如下:

名字位数
源端口号16 bit
目的端口号16 bit
序列号32 bit
确认号32 bit
TCP头长度4 bit
保留位6 bit
窗口大小16 bit
校验和16 bit
紧急指针16 bit
选项reserved
用户数据reserved
UDP协议

UDP协议是在传输层面向无连接的不可靠协议,报文格式如下:

名字位数
源端口号16 bit
目的端口号16bit
用户数据包长度16 bit
检查和16 bit
数据
TCP和UDP比较
连接性

TCP是面向连接的高可靠性协议,TCP协议客户端和服务端建立连接需要进行三次握手,断开连接需要进行四次握手.

UDP则是无连接的实时性协议,UDP协议并没有实质上的客户端服务端等,也无需建立连接,UDP只是将数据流发向某个区域,在区域内的所有设备都可以接收到数据.

可靠性

TCP协议有过程控制,在分包发包过程中会对包进行标记,不会出现后发先至的情况.
UDP协议设计上是尽最大努力进行数据传输,并不在乎数据接收端是否准确

报文首部

TCP协议因为可靠性的设计,报文首部相对较多
UDP协议因为数据交付为先的设计,报文首部只有必要数据,较为精简

双工性

TCP协议只能进行点对点的高可靠性全双工通信
UDP协议可以进行一对多,一对一,多对一和多对多等通信

应用场景
TCP协议

TCP协议由于其高可靠性的通信,一般应用于文件传输,网页或者通信软件等.

UDP协议

UDP协议由于其实时性,双工性和低性能开销,一般科应用于局域网查找设备,视频直播等场景.

相关代码

因为项目上用到的完整代码比较少,后面如果有时间在去补充
send

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <string.h>  
#include <errno.h>  
#include <sys/types.h>  

#define PORT	1617

int get_local_ip(char * ifname, char * ip)
{
    char *temp = NULL;
    int inet_sock;
    struct ifreq ifr;

    inet_sock = socket(AF_INET, SOCK_DGRAM, 0); 

    memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name));
    memcpy(ifr.ifr_name, ifname, strlen(ifname));

    if(0 != ioctl(inet_sock, SIOCGIFADDR, &ifr)) 
    {   
        perror("ioctl error");
        return -1;
    }

    temp = inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr);     
    memcpy(ip, temp, strlen(temp));

    close(inet_sock);

    return 0;
}


int main()
{
	setvbuf(stdout,NULL,_IONBF,0);
	fflush(stdout);
	
	int sd=-1;
	if((sd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
	{
		printf("socket error\n");
		return -1;
	}
	const int opt=1;
	int nb=0;
	nb = setsockopt(sd,SOL_SOCKET,SO_BROADCAST,(char *)&opt,sizeof(opt));
	if(nb == -1)
	{
		printf("set socket error\n");
		return -1;
	}

	struct sockaddr_in addr_to;
	bzero(&addr_to,sizeof(struct sockaddr_in));
	addr_to.sin_family=AF_INET;
	addr_to.sin_addr.s_addr=htonl(INADDR_BROADCAST);
	addr_to.sin_port=htons(PORT);
	int nlen=sizeof(addr_to);

	while(1)
	{
		sleep(1);
		char smsg[]={"I AM HERE\n"};
		int ret=sendto(sd,smsg,strlen(smsg),0,(struct sockaddr*)&addr_to,nlen);
		if(ret<0)
		{
			printf("send error\n");
		}
		else
		{
			printf("ok\n");
		}
	}

}

rec

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
  
#define PORT 1617

int main()  
{  
    setvbuf(stdout, NULL, _IONBF, 0);   
    fflush(stdout);   
  

    struct sockaddr_in addrto;  
    bzero(&addrto, sizeof(struct sockaddr_in));  
    addrto.sin_family = AF_INET;  
    addrto.sin_addr.s_addr = htonl(INADDR_ANY);  
    addrto.sin_port = htons(PORT);  
      
  
    struct sockaddr_in from;  
    bzero(&from, sizeof(struct sockaddr_in));  
    from.sin_family = AF_INET;  
    from.sin_addr.s_addr = htonl(INADDR_ANY);  
    from.sin_port = htons(PORT);  
      
    int sock = -1;  
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
    {     
        printf("socket error\n");   
        return -1;  
    }     
  
    const int opt = 1;  
 
    int nb = 0;  
    nb = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));  
    if(nb == -1)  
    {  
        printf("set socket error...\n");  
        return -1;  
    }  
  
    if(bind(sock,(struct sockaddr *)&(addrto), sizeof(struct sockaddr_in)) == -1)   
    {     
        printf("bind error...\n");  
        return -1;  
    }  
  
    int len = sizeof(struct sockaddr_in);  
    char smsg[100] = {0};  
  
    while(1)  
    {  
 
        int ret=recvfrom(sock, smsg, 100, 0, (struct sockaddr*)&from,(socklen_t*)&len);  
        if(ret<=0)  
        {  
            printf("read error....\n");  
        }  
        else  
        {         
            printf("%s\t", smsg);     
        }  
  
        sleep(1);  
    }  
  
    return 0;  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值