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 bytes | 20 bytes | 20 bytes | 4 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;
}