简介:网络分爲5层,软件开发需要用到的主要是上面两层:网络层,和应用层;路由器系统开发的估计需要用到传输层;所以如果研究网络的话,我们需要深入了解的是网络层和应用层;
关键字:网络层,应用层;
关键字解释:网络传输,可以想象成是快递包裹一样,快递有运输车(车里有快递箱,箱子里面有快递包裹,包裹表面有寄件单资讯,收件人根据这个来收到),这一层层的裹起来,就是不同层的职责所在,并非是爲了难爲我们这些学习网络的人;那麽,接下来,解释一下关键字:网络层是tcp/ip包裹的那一层,我们把原来的要发的data看作是物品的话,那麽网络层就是寄件单一样的东西,可以标志谁寄的,谁来收;而应用层是什麽呢?应用层是爲了简化或者说模式化网络层而出现的,更加方便包裹的这一层;
实战举例:我做的项目都是服务业自动化系统,这里会涉及到的最多的是socket,而通常socket编程就是针对网络层的,也就是通讯协议双方,制定protocol,这个protocol的内容是一些十六进制的编码,比如:
也就是在data的前面加上一些协议头,不同的头表示data所属的内容是什麽,这样拆包的那方就知道用什麽方式拆包了,比如我发了一个int过去,协议中説好了,这个是一个4byte的int,那麽对方就可以用int_32来把这个data转成4byte的int了,就拿到数字了;深挖一下:网络中的包都是二进制的,所以我们用十六进制来制定协议,因爲拆包的时候1个byte就是1个char;下面逐步讲解如何发送socket:
关键字:socket,server,client,listen,connect;
建server:首先需要建立一个监听用的server,server需要的是两个ip+port,ip就是我们的网络地址(分爲公网和局域网,往往我们看到的ip是局域网的,由路由器自动分配的,公网ip可以去google直接查,内部通讯可以用局域网ip,但是对外通讯需要用公网ip,一般与其他厂商通讯,都需要公网ip),port是监听端口,这个是因爲我们电脑中有很多程序,到底哪个程序来处理从外部来的data呢?这个就出现了每个程序可以监听一个或多个端口(port),端口从1到几万都可以,但是低位的(几十几百的)往往都是公约端口,这些已经被占了,请不要使用,也就是说,如果我自己写一个程序来监听某个端口的话,最好找个端口值设高一些,比如几千几万等等;设定好之後,就监听这个ip+port就好了;
建一个或者多个client:client端,直接connect到 server端;
收发讯息:read 和 write;一般实际处理的时候,是需要多綫程处理的,因爲主程序还是在跑,当有资讯来的时候,就拆包,当需要发资讯的时候,就封包;
下面看一下代码(c++的,linux系统,vscode,cmake跑的):
server:
打开监听端口:
void CallCarServer::Init()
{
int listenfd;//万物皆文件,请不要怀疑,所谓的监听端口,就是一个文件标识符(最原始的就是个int哟)
if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
ERR_EXIT("ERROR");
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(CAR_DRIVING_SERVER_NETWORK_TARGET_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
{
ERR_EXIT("SETSOCKOPT");
}
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
ERR_EXIT("ERROR");
}
if (listen(listenfd, SOMAXCONN) < 0)
{
ERR_EXIT("LISTEN");
}
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn;
char sendbuf[256];
while (true)
{
conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen);
if (conn < 0)
{
ERR_EXIT("accept");
}
printf("ip = %s, port = %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
conn_ = conn;
std::thread t_receive(&CallCarServer::thread_accept, this);
t_receive.detach();
}
close(listenfd);
}
多执行绪处理数据:
void CallCarServer::thread_accept()
{
char recvbuf[BUFF_SIZE];
while (true)
{
sleep(1);
memset(recvbuf, 0, sizeof(recvbuf));
int num = read(conn_, recvbuf, sizeof(recvbuf));
if (num <= 0)
{
continue;
}
printf("message length is %d\n", num);
//take the length of message
//int len = Lenth_Message(recvbuf);
//len = num-4;
char *message = new char(num - 4);
for (int i = 0; i < len; i++)
{
message[i] = recvbuf[i + 4];
}
// DealMessage(message);
ReceiveBuf *recvbuf = reinterpret_cast<ReceiveBuf *>(message);
std::cout<< recvbuf->message.iCarID<<std::endl;
delete (message);
//SendCarGo(conn);
}
close(conn_);
}
client端:
int sock;
if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
{
ERR_EXIT("ERROR");
}
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(2978);
servaddr.sin_addr.s_addr = inet_addr("192.168.200.243");
if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
{
ERR_EXIT("connect");
}
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
{
write(sock,sendbuf,strlen(sendbuf));
memset(sendbuf,0,sizeof(sendbuf));
}
close(sock);
上面是基本知识,实战中,花更多时间的是制定protocol,下篇再讲解如何制定protocol;
以及可能大部分人使用的是应用层的network program:比如mqtt,http post等;
<<: [Day09] Tableau 轻松学 - Data Source 页面
0x1 前言 废话不多说,今日流程如下先观察传进内容,在针对内容刻画面 0x2 建立 Route 跟...
今天邀请到来自新化高中的 Colten 来分享他在高中竞程这条路上的种种历程。本次访谈有公开浏览,欢...
不怎麽重要的前言 上一篇我们介绍了什麽是指标,不晓得大家有没有比较了解地址的概念? 接下来我们来介绍...
前情提要 倒在路边的我,醒来发现人早已不见,只好回家过节。 (时间来到了,回到家中的午餐後) **我...
前言 「眼前的黑不是黑,你说的白是什麽白」-- 你是我的眼(萧煌奇) 没错,并非所有图片都是在理想的...