1.TCP,UDP的对比图
TCP:面向连接的,可靠的,字节流服务;
UDP:无连接的,不可靠的,数据报服务;
2.补充网络部分的其他知识点
1).复位报文段
在某些特殊条件下, TCP 连接的一端会向另一端发送携带 RST 标志的报文段,即复位报文段,已通知对方关闭连接或重新建立连接。这里介绍一下三种情况:
1)当户端端程序访问一个不存在的端口时,目标主机给它发送一个复位报文段。
2)异常终止连接。正常情况下,数据交换完成之后,一方给另一方发送 FIN 结束报文段。 TCP 提供了异常终止一个连接的方法,即给对方发送一个复位报文段。一但发送了复位报文段,发送端所有排队等待发送的数据都将被丢弃。应用程序可以使用socket 选项SO_LINGER 来设置发送复位报文段,以异常终止连接。
- 处理半打开连接。例如 TCP 一端关闭了连接, 由于网络故障对方没有收到结束报文,对方误以为连接仍然正常。处于这种状态的连接称为半打开连接。此时如果对端向连接写入数据,则会收到本端回复的复位报文段.
2).交互数据流与成块数据流
TCP 按照携带应用程序数据长度可以分为两种:交互数据和成块数据。交互数据仅包含很少的字节。使用交互数据的应用程序对实时性要求极高,比如 telnet、 ssh 等。
成块数据的长度则通过为 TCP 报文段允许的最大数据长度。使用成块数据的应用程序对传输效率要求高,比如 FTP。
3).带外数据
有些传输层协议具有带外(out of Band,OOB)数据的概念,用于迅速通告对方本端发生的重要事件。因此,带外数据比普通数据有更高的优先级,它应该总是立即被发送,而不论发送缓冲区中是否有排队等待发送的普通数据。
带外数据的传输可以使用一条独立的传输层连接,也可以映射到传输普通数据的连接中.实际应用中,带外数据的使用很少见,已知的仅有telnet,ftp等远程非活跃程序.
UDP没有实现带外数据传输,TCP也没有真正的带外数据.不过TCP利用头部中的紧急指针标志和紧急指针两个字段,给应用程序提供了一种传输紧急数据的方式。一般只有一个字节数据。 TCP的紧急方式利用传输普通数据的连接来传输紧急数据.这种紧急数据的含义和带外数据类似,因此后文也将TCP紧急数据称为带外数据.
4).recv和send的最后一个参数
recv和send最后一个参数flag为数据的收发提供了额外的控制,它可以取下图所示选项中的一个或几个的逻辑或.
如果不用flag,完全可以用read,write代替(但是网络这里建议还是用send和recv):
//服务器端:
...
char buff[128];
// recv(c,buff,127,0);read(c,buff,127);printf("buff=%s\n",buff);// send(c,"ok",2,0);write(c,"ok",2);
...//客户端
...printf("input:\n");char buff[128];fgets(buff,127,stdin);// send(sockfd,buff,strlen(buff),0); write(sockfd,buff,strlen(buff)); memset(buff,0,128);//recv(sockfd,buff,127,0);read(sockfd,buff,127);printf("read:%s\n",buff);
...
5).高性能服务器程序框架:C/S模型
TCP/IP协议在设计和实现上并没有客户端和服务器的概念,在通信过程中所有机器都是对等的.但由于资源(视频,新闻,软件等)都被数据提供者所垄断,所以几乎所有的网络应用程序都很自然地采用了如下图所示的C/S(客户端/服务器)模型:所有客户端都通过访问服务器来获取所需的资源.
6).高性能服务器程序框架:p2p模型
P2P(Peer to Peer,点对点)模型比C/S模型更符合网络通信的实际情况.它摒弃了以服务器为中心的格局,让网络上所有主机重新回归对等的地位.
P2P模型使得每台机器再消耗服务的同时也给别人提供服务.这样资源能够充分,自由地共享.云计算机群可以看作P2P模型地一个典范.但P2P模型的缺点也很明显:
当用户之间传输的请求过多时,网络的负载将加重.
下图所示的P2P模型存在一个显著的问题,即主机之间很难互相发现,所以实际使用的P2P模型通常带有一个专门的发现服务器,这个发现服务器通常还提供查找服务(甚至还可以提供内容服务),使每个客户都能尽快地找到自己需要的资源.
从编程角度来讲,P2P模型可以看作C/S模型的扩展:每台主机即是客户端,又是服务器端.因此,我们仍然采用C/S模型来讨论网络编程.
7)套接字API
套接字API最初是为Unix操作系统开发的,但现在几乎所有的操作系统和语言中都有其变体存在.
所以socket编程流程显得尤为重要;
tcp编程流程:socket,bind,listen,accept,recv,send,close(7步); socket,connect,send,recv,close(5步);
udp编程流程:socket,bind,recvfrom,sendto,close(5步); socket,sendto,recvfrom,close(4步);
8)TIME_WAIT补充
3.HTTP 协议与 web 服务器
1).浏览器与服务器通信过程
浏览器与 web 服务器在应用层通信使用的是 HTTP 协议(超文本传输协议),而 HTTP协议在传输层使用的是 TCP 协议。那么浏览器需要和 web 服务器三次握手建立连接后,才可以发送 HTTP 请求报文,服务器收到请求报文后,向浏览器回复 HTTP 应答报文。
浏览器向服务器发起连接前,需要得到服务器的 IP 及端口。用户在浏览器中通常只输入网址(网站域名) ,浏览器会通过 DNS 服务查询获取到服务器的 IP 地址。 对于端口来讲,使用 HTTP 协议的程序一般默认使用 80 端口。
浏览器服务器建立连接后,如果两次以上的请求复用同一个 TCP 连接,则称之为长连接。如果浏览器发送一次请求报文,服务器回复一次应答就断开连接,下次交互再重新进行三次握手建立连接,那么就被称作短连接。使用长连接显然是更好一些,可以减少网络中的同步报文,也使得服务器的响应速度变快。
http属于应用层,它在传输层使用的是tcp协议;
传输层协议:tcp 协议和udp协议;
2).常见的 web 服务器有:
◼ Apache: 简单、速度快、性能稳定,并可做代理服务器使用
◼ IIS(Internet Information Server):安全性、强大、灵活
◼ Nginx:小巧而高效,可以做高效的负载均衡反向代理
◼ Tomcat:技术先进、性能稳定、免费
3).浏览器与服务器通信过程(面试重点)
a)浏览器与服务器通信过程
(1)浏览器从URL中解析出服务器的主机名.
(2)浏览器将服务器的主机名转换成服务器的IP地址;
(3)浏览器将端口号(如果有的话)从URL中解析出来.
(4)浏览器建立一条与Web服务器的TCP连接;
(5)浏览器向服务器发送一条HTTP请求报文;
(6)服务器向浏览器回送一条HTTP响应报文;
(7)关闭连接,浏览器显示文档;
b)DNS
域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用UDP端口53。
浏览器要将URL解析为IP地址,解析域名就要用到DNS协议,首先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。DNS查询分为两种方式,一种是递归查询,一种是迭代查询。如果是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名 服务器发送查询请求,然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。
以下内容了解即可.
c)URL
URL:统一资源定位符,URL是资源标识符最常见的形式.
URL描述了一台特定服务器上某资源的特定位置.它们可以明确说明如何从一个精确,固定的位置获取资源.
自己实现HTTP服务器
简单版:
理解HTTP服务器编程流程;
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>
#include <fcntl.h>
int create_socket()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(80);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));if(res==-1){return -1;}res=listen(sockfd,5);if(res==-1){return -1;}return sockfd;}
int main()
{int sockfd=create_socket();assert(sockfd!=-1);struct sockaddr_in caddr;int len=-1;int c=-1;while(1){len=sizeof(caddr);c=accept(sockfd,(struct sockaddr *)&caddr,&len); if(c<0) {continue; }char buff[1024]={0}; int n=recv(c,buff,1023,0); printf("n=%d,read:\n",n); printf("%s\n",buff); send(c,"welcome to quzijie!",19,0); close(c);//短链接 }exit(0);
}
本篇完!🍗