10.0 对网络协议的知识的相关复习
10.0 对网络协议的知识的相关复习
计算机中的网络实际上它对应了两种基本的模型,一种是OSI七层模型,从上到下分别是应用层,表示层,会话层,传输层,网络层,链路层和物理层。那如果是OSI的五层模型,那么就是应用层,传输层,网络层,链路层和物理层。以五层模型为例,这里做一个说明:
应用层:应用层是用于直接处理和用户打交道的一些网络接口,例如Http,SMTP,FTP,DNS这些所提供的服务。这些是能够直接看得到的。与网络应用相关的一些接口。
传输层:传输层则提供了端到端的连接,例如TCP协议和UDP协议,前者是面向数据流的且可靠的数据传输,它也支持流量控制和拥塞控制机制以及超时重传等机制来保证数据传输的完整性。TCP协议常被用在一些对数据完整性要求较高的场合中,比如文件传输,消息的发送等。而UDP协议则是一种非面向连接的,且基于数据报传输的不可靠的协议,这种协议的典型特征就是速度快,但很难保证发送出去的数据的完整性。它常常被用在一些对速度要求高,但对数据的完整性不怎么关切的场合中。例如视频传输、视频通话等。
网络层:网络层则位于传输层之下,它负责数据包的路由以及负责讲数据路由到正确的网络节点中,IP地址就在这一层扮演了重要的角色。
链路层:链路层决定了数据包如何在网络链路中传输,包括了MAC地址的识别和错误检测。
物理层:在这一层,数据以比特的形式在网络介质上进行传输,比如网络电缆,光纤等传输介质,在这一层上传输的对象是比特流。
案例:基于原始Socket套接字API的TCP命令行文件传输程序
该命令行程序的server端用于接收文件,并将文件保存在命令行参数中所指定的目录中。而客户端则根据发送的文件,以及目标server的IP地址和端口号来向服务端发送文件。
(1)server.cpp如下文所示:
#include<iostream>
#include<fstream>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
using namespace std;
int main(int argc,char*argv[])
{
//server savePath
if(2 == argc)
{
//1.创建套接字
int serverSocket = socket(AF_INET,SOCK_STREAM,0);
if(-1 == serverSocket)
{
cout << "socket Create Error!" << endl;
}
//2.绑定IP地址
sockaddr_in serverAddr = {0};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
int bindRtn = bind(serverSocket,(const sockaddr*)&serverAddr,sizeof(serverAddr));
if(bindRtn != 0)
{
cerr << "bind error!" << endl;
return -2;
}
//3.监听
int listenRtn = listen(serverSocket,500);
if(listenRtn != 0)
{
cerr << "listen error!" << endl;
return -3;
}
START:
//4.accept连接
sockaddr_in clientAddr = {0};
socklen_t clientLen = sizeof(clientAddr);
int clientSocket = accept(serverSocket,(sockaddr*)&clientAddr,&clientLen);
if(clientSocket == -1)
{
cerr << "accept error!" << endl;
}
cout << "Client:[" << inet_ntoa(clientAddr.sin_addr) << ":" << clientAddr.sin_port << "]" << endl;
//5.接受数据
///5.1 先接收文件名
char fileName[1024] = {0};
ssize_t fileNameLength = recv(clientSocket,fileName,sizeof(fileName),0);
cout << "文件名:" << fileName << ",文件名字符串长度" << fileNameLength-1 << endl;
///5.2 接受文件体
string filePath(argv[1]);
filePath += '/';
filePath += fileName;
cout << "文件将被保存在:" << filePath << endl;
fstream fileOut(filePath,ios::out|ios::binary);
if(!fileOut)
{
cerr << "文件创建失败!" << endl;
return -3;
}
char buf[4096] = {0};
ssize_t recvLength = 0;
while((recvLength = recv(clientSocket,buf,sizeof(buf),0)) > 0)
{
fileOut.write(buf,recvLength);
}
close(clientSocket);
fileOut.close();
goto START;
close(serverSocket);
}
else
{
cout << "Usage:[server fileSavePath]" << endl;
return 1;
}
return 0;
}
(2)client.cpp如下所示
#include<iostream>
#include<unistd.h>
#include<fstream>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/socket.h>
using namespace std;
int main(int argc,char*argv[])
{
//client fileName IP Port
if(4 == argc)
{
//1.创建socket
int clientSocket = socket(AF_INET,SOCK_STREAM,0);
if(clientSocket == -1)
{
cerr << "Client Socket Create Error!" << endl;
}
//2.配置服务端IP
sockaddr_in serverAddr = {0};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(atoi(argv[3]));
inet_aton(argv[2],&serverAddr.sin_addr);
cout << "目标:[" << inet_ntoa(serverAddr.sin_addr) << ":" << serverAddr.sin_port << "]" << endl;
//3.连接
int connectRtn = connect(clientSocket,(const sockaddr*)&serverAddr,sizeof(serverAddr));
if(connectRtn != 0)
{
cerr << "connect faild!" << endl;
return -1;
}
//4.先发送文件名
char fname[512] = {0};
strcpy(fname,argv[1]);
ssize_t fileNameLength = send(clientSocket,fname,strlen(fname),0);
cout << "发送文件名:" << argv[1] << ",文件名长度" << fileNameLength << endl;
//5.发送文件体
fstream fileIn(argv[1],ios::in|ios::binary);
size_t readBytes = 0;
char buf[4096] = {0};
do
{
fileIn.read(buf,sizeof(buf));
readBytes = fileIn.gcount();
send(clientSocket,buf,readBytes,0);
}while(readBytes > 0);
close(clientSocket);
fileIn.close();
}
else
{
cout << "Usage:[client fileName IP Port]" << endl;
return -1;
}
return 0;
}
(3)先运行server,,再运行client进行文件发送和接收测试

本节代码:https://files.cnblogs.com/files/blogs/792763/SocketConnection.zip?t=1720348166&download=true

浙公网安备 33010602011771号