PS:这些文字是参考的UNP写的,但是网络分层的原理都是一样的,并且懒得专门去写一个关于Windows的了,所以就这样~~
网络分层
网络是分层的,程序员关心的是以下4层:
- 以太网层:帧,frame
- IP层:分组,package
- TCP:节,segment
- 应用层:消息,message
在谈论网络数据的时候,如果说到帧,则应该知道是以太网层。我们一般关心的是TCP——分节,应用层——消息。
TCP/IP协议不仅仅指的是TCP协议和IP协议,它泛指那些为应用层提供服务的网络协议。其中典型的TCP、UDP工作在传输层,IP协议工作在TCP和UDP下层的网络层。因此可以说网络层是为传输层提供服务的,而传输层则是为应用层提供服务的。一般很少直接使用网络层进行编程,但是也可以使用原始套接字来跳过传输层来直接使用网络层进行编程。
七层网络模型
所谓7层网络模型是指的 OSI 7层网络模型——应用程、表示层、会话层、传输层、网络层、数据链路层、物理层。各个层的作用如下:
OSI | 功能 | TCP/IP协议 |
---|---|---|
应用程 | 文件传输、电子邮件、文件服务、虚拟终端 | TFTP、HTTP、SNMP、FTP、SMTP、DNS、Telnet |
表示层 | 数据格式化、代码转换、数据加密 | 无协议 |
会话层 | 解除或建立与其他节点的联系 | 无协议 |
传输层 | 提供端对端的接口 | TCP、UDP、原始套接字 |
网络层 | 为数据包选择路由 | IP、ICMP、RIP、OSPF、BGP、IGMP |
数据链路层 | 传输有地址的帧、错误检测 | SLIP,CSLIP、PPP、ARP、RARP、MTU |
物理层 | 以二进制形式在屋里媒介上传输数据 | ISO2110、IEEE802 |
从上面表格可以看出,应用层进行数据传输一般使用某个协议通信,这些协议是在TCP或UDP的基础上实现的,比如DNS在使用TCP承载应用数据时在每个要发送的记录之前防止一个二进制的计数值,给出这个记录的长度。一般而言,可以将顶三层都划分为应用程,它属于用户进程,顶三层处理具体的网络应用的所有细节,而不关心通信的细节,底四层则属于内核进程,用于发送数据、等待确认、给无序到达的数据排序、计算并验证校验和等待,它并不在意具体的网络应用,它在传输层则使用TCP或者UDP进行通信。unix网络编程主要介绍TPC协议,同时也涉及UDP和原始套接字。
一个例子
// 获取时间客户端程序
// intro/daytimetcp_client.c
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "../unp.h"
int main(int argc,char *argv[])
{
int sockfd,n;
char recvline[MAXLINE + 1];
struct sockaddr_in serveraddr;
if (argc != 2)
{
err_quit("usage:%s <ip>",argv[0]);
}
for (size_t i = 0; i < argc; i++)
{
printf("arv[%d] = %s\r\n",i,argv[i]);
}
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
err_sys("socket error:");
}
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(13);
if (inet_pton(AF_INET,argv[1],&serveraddr.sin_addr) <= 0)
{
err_quit("inet_pton error for %s",argv[1]);
}
if (connect(sockfd,(SA *)&serveraddr,sizeof(serveraddr)) < 0)
{
err_sys("connect error");
}
while ((n = read(sockfd,recvline,MAXLINE)) > 0)
{
recvline[n] = 0;
if (fputs(recvline,stdout) == EOF)
{
err_sys("fputs error");
}
}
if (n < 0)
{
err_sys("read error");
}
return 0;
}
// intro/daytimetcp_server.c
#include "../unp.h"
#include <time.h>
int main(int argc,char *argv[]){
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if (listenfd <= 0)
{
err_sys("listen error");
}
char buf[MAXLINE];
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(TIME_SERVER_LISTEN_PORT);
serveraddr.sin_family = AF_INET;
if (bind(listenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)) != 0)
{
err_sys("bind error");
}
int nret = listen(listenfd,LISTENQ);
if (nret < 0)
{
err_sys("listen error");
}
while (1)
{
int connectfd = accept(listenfd,(struct sockaddr *)NULL,NULL);
if (connectfd < 0)
{
err_sys("accept error");
}
time_t ticks = time(NULL);
snprintf(buf,sizeof(buf),"%.24s\r\n",ctime(&ticks));
printf(buf);
int nWrite = 0;
int length = strlen(buf);
int npos = 0;
while (length > 0)
{
nWrite = write(connectfd,buf + npos,strlen(buf) - npos);
if (nWrite > 0)
{
length -= nWrite;
npos += nWrite;
}
else if (nWrite != EINTR)
{
err_sys("write");
}
}
close(connectfd);
}
return 0;
}