计算机网络知识点

一、计算机网络基础

1、互联网的组成以及几种网络传输方式

  • 边缘部分:由所有连接在互联网上的主机构成。这部分是用户直接使用的,用来通讯和数据共享。计算机之间的通讯有两种,一种是客户-服务器方式,一种是P2P方式。
  • 核心部分:由大量网络和连接这些网络的路由器组成。这部分是为边缘部分提供服务。核心中起重要作用的是路由器,他的作用是分组交换,转发收到的分组。

2、数据交换的几种方式和特点:

  1. 电路交换,需要进行建立连接、通话、释放连接三个过程。资源独占,线路传输的效率较低。
  2. 报文交换,整个报文传递到临近节点,全部存储下来后在查找转发表,然后转发到下一个节点。
  3. 分组交换,需要将数据报文切分成较小的等长数据块,加入必要的控制信息,构成每一个分组,每一个分组独立传输。分组交换高效,灵活,迅速,可靠,但是也带来了时延和一些不必要的开销。

在这里插入图片描述

3、OSI网络体系结构与TCP/IP协议模型

​ 网络协议通常分不同层次进行开发,每一层分别负责不同的通信功能。

我们知道TCP/IP与OSI最大的不同在于:OSI是一个理论上的网络通信模型,而TCP/IP则是实际上的网络通信标准。但是,它们的初衷是一样的,都是为了使得两台计算机能够像两个知心朋友那样能够互相准确理解对方的意思并做出优雅的回应。现在,我们对OSI七层模型的各层进行简要的介绍:
在这里插入图片描述

3.1、物理层(physical layer)[比特流]

参考模型的最低层,也是OSI模型的第一层,实现了相邻计算机节点之间比特流的透明传送,并尽可能地屏蔽掉具体传输介质和物理设备的差异,使其上层(数据链路层)不必关心网络的具体传输介质。

3.2、数据链路层(data link layer)[帧]

接收来自物理层的位流形式的数据,并封装成帧,传送到上一层;同样,也将来自上层的数据帧,拆装为位流形式的数据转发到物理层。
  这一层在物理层提供的比特流的基础上,通过差错控制、流量控制方法,使有差错的物理线路变为无差错的数据链路,即提供可靠的通过物理介质传输数据的方法。
  
  该层通常又被分为介质访问控制(MAC)和逻辑链路控制(LLC)两个子层

  • MAC子层的主要任务是解决共享型网络中多用户对信道竞争的问题,完成网络介质的访问控制。
  • LLC子层的主要任务是建立和维护网络连接,执行差错校验、流量控制和链路控制。

3.3、网络层(network layer)[包或IP数据报]

将网络地址翻译成对应的物理地址,并通过路由选择算法为分组通过通信子网选择最适当的路径。
  在这里插入图片描述

3.4、传输层(transport layer)[TCP:报文段,UDP:用户数据报]

在源端与目的端之间提供可靠的透明数据传输,使上层服务用户不必关系通信子网的实现细节。在协议栈中,传输层位于网络层之上,传输层协议为不同主机上运行的进程提供逻辑通信,而网络层协议为不同主机提供逻辑通信,如下图所示。
  在这里插入图片描述
  实际上,网络层可以看作是传输层的一部分,其为传输层提供服务。但对于终端系统而言,网络层对它们而言是透明的,它们知道传输层的存在,也就是说,在逻辑上它们认为是传输层为它们提供了端对端的通信,这也是分层思想的妙处。

3.5、会话层(Session Layer)

会话层是OSI模型的第五层,是用户应用程序和网络之间的接口,负责在网络中的两节点之间建立、维持和终止通信。

3.6、表示层(Presentation Layer)

数据的编码,压缩和解压缩,数据的加密和解密。
表示层是OSI模型的第六层,它对来自应用层的命令和数据进行解释,以确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。

3.7、应用层(Application layer)[报文]

为用户的应用进程提供网络通信服务。

3.8、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,IEEE802.2

在这里插入图片描述

4、数据的封装

在这里插入图片描述

5、IP地址的分类

在这里插入图片描述

6、网关、网桥和路由器

  • 网关是一个链接两种不同协议簇的进程,为某一个特定的应用提供服务。
  • 网桥是在数据链路层对网络进行互联的。
  • 路由器是在网络层对网络进行互联的。

在TCP/IP协议簇中,IP层使用不可靠的服务,TCP提供可靠的服务,为了提供可靠到的服务,TCP采用了超时重传,发送和接收端到端的确认分组机制。

二、Http和Https的区别

  • Http协议运行在TCP之上,明文传输,客户端与服务器端都无法验证对方的身份。
  • Https是身披SSL(Secure Socket Layer)外壳的Http,运行于SSL上,SSL运行于TCP之上,是添加了加密和认证机制的HTTP。

二者之间存在如下不同:

  • 端口不同:Http与Http使用不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • 资源消耗:和HTTP通信相比,Https通信会由于加减密处理消耗更多的CPU和内存资源。
  • 开销:Https通信需要证书,而证书一般需要向认证机构购买。
  • Https的加密机制是一种共享密钥加密和公开密钥加密并用的混合加密机制。

三、对称加密与非对称加密

  • 对称密钥加密是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方。
  • 而非对称加密是指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。

由于非对称加密的方式不需要发送用来解密的私钥,所以可以保证安全性;但是和对称加密比起来,它非常的慢,所以我们还是要用对称加密来传送消息,但对称加密所使用的密钥我们可以通过非对称加密的方式发送出去。

四、三次握手与四次挥手

4.1、三次握手

(我要和你建立链接,你真的要和我建立链接么,我真的要和你建立链接,成功)

第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。

第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。

第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
在这里插入图片描述

4.2、 四次挥手

(我要和你断开链接;好的,断吧。我也要和你断开链接;好的,断吧)
第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。此时TCP链接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。

第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
在这里插入图片描述

4.3、为什么TCP链接需要三次握手,两次不可以么,为什么?

为了防止 已失效的链接请求报文突然又传送到了服务端,因而产生错误。

客户端发出的连接请求报文并未丢失,而是在某个网络节点长时间滞留了,以致延误到链接释放以后的某个时间才到达Server。这是,Server误以为这是Client发出的一个新的链接请求,于是就向客户端发送确认数据包,同意建立链接。若不采用“三次握手”,那么只要Server发出确认数据包,新的链接就建立了。由于client此时并未发出建立链接的请求,所以其不会理睬Server的确认,也不与Server通信;而这时Server一直在等待Client的请求,这样Server就白白浪费了一定的资源。若采用“三次握手”,在这种情况下,由于Server端没有收到来自客户端的确认,则就会知道Client并没有要求建立请求,就不会建立链接。

4.4、为什么是4次挥手?

因为TCP有个半关闭状态,假设A.B要释放连接,那么A发送一个释放连接报文给B,B收到后发送确认,这个时候A不发数据,但是B如果发数据A还是要接受,然后B还要发给A连接释放报文,然后A发确认,所以是4次。

五、TCP协议如何来保证传输的可靠性

TCP提供一种面向连接的、可靠的字节流服务。其中,面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信;而字节流服务意味着两个应用程序通过TCP链接交换8bit字节构成的字节流,TCP不在字节流中插入记录标识符。

对于可靠性,TCP通过以下方式进行保证:

  • 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;
  • 对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;
  • 丢弃重复数据:对于重复数据,能够丢弃重复数据;
  • 应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
  • 超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;

流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。

六、客户端不断进行请求链接会怎样?DDos(Distributed Denial of Service)攻击?

服务器端会为每个请求创建一个链接,并向其发送确认报文,然后等待客户端进行确认。

6.1、DDos 攻击

  • 客户端向服务端发送请求链接数据包。
  • 服务端向客户端发送确认数据包。
  • 客户端不向服务端发送确认数据包,服务器一直等待来自客户端的确认。

6.2、DDos 预防 ( 没有彻底根治的办法,除非不使用TCP )

  • 限制同时打开SYN半链接的数目。(TCP存在半连接状态)
  • 缩短SYN半链接的Time out 时间。
  • 关闭不必要的服务。

七、TCP与UDP的区别

TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议,它们之间的区别包括:

  • TCP是面向连接的,UDP是无连接的;
  • TCP是可靠的,UDP是不可靠的;
  • TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多的通信模式;
  • TCP是面向字节流的,UDP是面向报文的;
  • TCP有拥塞控制机制;UDP没有拥塞控制,适合媒体通信;
  • TCP首部开销(20个字节)比UDP的首部开销(8个字节)要大;

八、TCP的流量控制和拥塞处理

8.1、TCP流量控制

原因::如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。
原理:是利用滑动窗口实现的 ,接收方告诉发送方自己的接收窗口大小,然后发送方发送窗口不能超过接收方给出的接收窗口值。

8.2、TCP拥塞控制

原因:过多的数据发送到网络中使得路由器或者链路过载
方法:慢开始,拥塞避免,快重传,快恢复
原理:
慢开始和拥塞避免 发送方维持一个拥塞窗口 cwnd ( congestio n window )的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞。
发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。 慢开始算法:当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口 cwnd ,可以使分组注入到网络的速率更加合理。

快重传和快恢复 如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。这时,TCP马上把拥塞窗口cwnd 减小到1,并执行慢开始算法,同时把慢开始门限值ssthresh减半。这是不使用快重传的情况。 快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。

计算机网络中的带宽、交换结点中的缓存及处理机等都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏,这种情况就叫做拥塞。拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。
  注意,拥塞控制和流量控制不同,前者是一个全局性的过程,而后者指点对点通信量的控制。拥塞控制的方法主要有以下四种:

  1. 慢启动:不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。
  2. 拥塞避免:拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长。

在这里插入图片描述

  1. 快重传:快重传要求接收方在收到一个 失序的报文段 后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。

在这里插入图片描述

  1. 快恢复:快重传配合使用的还有快恢复算法,当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半,但是接下去并不执行慢开始算法:因为如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。

九、TCP状态转移

在这里插入图片描述

  1. CLOSED:起始点,在超时或者连接关闭时候进入此状态。
  2. LISTEN:svr端在等待连接过来时候的状态,svr端为此要调用socket, bind,listen函数,就能
    进入此状态。此称为应用程序被动打开(等待客户端来连接)。
  3. SYN_SENT:客户端发起连接,发送SYN给服务器端。如果服务器端不能连接,则直接进入 CLOSED状态。
  4. SYN_RCVD:跟3对应,服务器端接受客户端的SYN请求,服务器端由LISTEN状态进入SYN_RCVD状态。同时服务器端要回应一个ACK,同时发送一个SYN给客户端;另外一种情况,客户端在发起SYN的同时接收到服务器端得SYN请求,客户端就会由SYN_SENT到SYN_RCVD状态。
  5. ESTABLISHED:服务器端和客户端在完成3次握手进入状态,说明已经可以开始传输数据 了。

以上是建立连接时服务器端和客户端产生的状态转移说明。相对来说比较简单明了,如果你对三次握手比较熟悉,建立连接时的状态转移还是很容易理解。接下来服务器端和客户端就进行数据传输。
下面,我们来看看连接关闭时候的状态转移说明,关闭需要进行4次双方的交互,还包括要处
理一些善后工作(TIME_WAIT状态),注意,这里主动关闭的一方或被动关闭的一方不是指
特指服务器端或者客户端,是相对于谁先发起关闭请求来说的:

  1. FIN_WAIT_1:主动关闭的一方,由状态5进入此状态。具体的动作时发送FIN给对方。
  2. FIN_WAIT_2:主动关闭的一方,接收到对方的FIN ACK,进入此状态。由此不能再接收对方 的数据。但是能够向对方发送数据。
  3. CLOSE_WAIT:接收到FIN以后,被动关闭的一方进入此状态。具体动作时接收到FIN,同 时发送ACK。
  4. LAST_ACK:被动关闭的一方,发起关闭请求,由状态8进入此状态。具体动作时发送FIN
    给对方,同时在接收到ACK时进入CLOSED状态。
  5. CLOSING:两边同时发起关闭请求时,会由FIN_WAIT_1进入此状态。具体动作是,接收 到FIN请求,同时响应一个ACK。

TIME_WAIT:最纠结的状态来了。从状态图上可以看出,有3个状态可以转化成它,我们来分析:
a.由FIN_WAIT_2进入此状态:在双方不同时发起FIN的情况下,主动关闭的一方在完成自身发
起的关闭请求后,接收到被动关闭一方的FIN后进入的状态。
b.由CLOSING状态进入:双方同时发起关闭,都做了发起FIN的请求,同时接收到了FIN并做了
ACK的情况下,由CLOSING状态进入。
c.由FIN_WAIT_1状态进入:同时接受到FIN(对方发起),ACK(本身发起的FIN回应),与
b的区别在于本身发起的FIN回应的ACK先于对方的FIN请求到达,而b是FIN先到达。这种情
况概率最小。
关闭的4次连接最难理解的状态是TIME_WAIT,存在TIME_WAIT的2个理由:
1.可靠地实现TCP全双工连接的终止。
2.允许老的重复分节在网络中消逝。

十、从输入网址到获得页面的过程

  1. 浏览器查询DNS,获取域名对应的IP地址:具体过程包括浏览器搜索自身的DNS缓存、搜索操作系统的DNS缓存、读取本地的Host文件和向本地DNS服务器进行查询等。对于向本地DNS服务器进行查询,如果要查询的域名包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析(此解析具有权威性);如果要查询的域名不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析(此解析不具有权威性)。如果本地域名服务器并未缓存该网址映射关系,那么将根据其设置发起递归查询或者迭代查询;
  2. 浏览器获得域名对应的IP地址以后,浏览器向服务器请求建立链接,发起三次握手;
  3. TCP/IP链接建立起来后,浏览器向服务器发送HTTP请求;
  4. 服务器接收到这个请求,并根据路径参数映射到特定的请求处理器进行处理,并将处理结果及相应的视图返回给浏览器;
  5. 浏览器解析并渲染视图,若遇到对js文件、css文件及图片等静态资源的引用,则重复上述步骤并向服务器请求这些资源;
  6. 浏览器根据其请求到的资源、数据渲染页面,最终向用户呈现一个完整的页面。

十一、理解Cookie和Session的区别及使用

前言

HTTP是一种无状态的协议,为了分辨链接是谁发起的,需自己去解决这个问题。不然有些情况下即使是同一个网站每打开一个页面也都要登录一下。而Session和Cookie就是为解决这个问题而提出来的两个机制。

应用场景

登录网站,今天输入用户名密码登录了,第二天再打开很多情况下就直接打开了。这个时候用到的一个机制就是cookie。
session一个场景是购物车,添加了商品之后客户端处可以知道添加了哪些商品,而服务器端如何判别呢,所以也需要存储一些信息就用到了session。

1、Cookie

  • 通俗讲,是访问某些网站后在本地存储的一些网站相关信息,下次访问时减少一些步骤。更准确的说法是:Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一服务器,是在客户端保持状态的方案。
  • Cookie的主要内容包括:名字,值,过期时间,路径和域。使用Fiddler抓包就可以看见,比方说我们打开百度的某个网站可以看到Headers包括Cookie,如下:
BIDUPSID: 9D2194F1CB8D1E56272947F6B0E5D47E 
PSTM: 1472480791 
BAIDUID: 3C64D3C3F1753134D13C33AFD2B38367:FG 
ispeed_lsm: 2 
MCITY: -131: 
pgv_pvi: 3797581824 
pgv_si: s9468756992 
BDUSS: JhNXVoQmhPYTVENEdIUnQ5S05xcHZMMVY5QzFRNVh5SzZoV0xMVDR6RzV-bEJZSVFBQUFBJCQAAAAAAAAAAAEAAACteXsbYnRfY2hpbGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALlxKVi5cSlYZj 
BD_HOME: 1 
H_PS_PSSID: 1423_21080_17001_21454_21408_21530_21377_21525_21193_21340 
BD_UPN: 123253 
sug: 3 
sugstore: 0 
ORIGIN: 0 
bdime: 0
  • key,value形式。过期时间可设置的,如不设,则浏览器关掉就消失了,存储在内存当中,否则就按设置的时间来存储在硬盘上的,过期后自动清除,比方说开关机关闭再打开浏览器后他都会还存在,前者称之为Session cookie 又叫 transient cookie,后者称之为Persistent cookie 又叫 permenent cookie。路径和域就是对应的域名,a网站的cookie自然不能给b用。

2、Session

  • 存在服务器的一种用来存放用户数据的类HashTable结构。
  • 浏览器第一次发送请求时,服务器自动生成了一个HashTable和一个Session ID来唯一标识HashTable,并将其通过响应发送到浏览器。浏览器第二次发送请求会将前一次服务器响应中的Session ID放在请求中一并发送到服务器上,服务器从请求中提取出Session ID,并和保存的所有Session ID进行对比,找到这个用户对应的HashTable。
  • 一般这个值会有个时间限制,超时后毁掉这个值,默认30分钟。
  • 当用户在应用程序的 Web页间跳转时,存储在 Session 对象中的变量不会丢失而是在整个用户会话中一直存在下去。
  • Session的实现方式和Cookie有一定关系。建立一个连接就生成一个session ID,打开几个页面就好几个了,这里就用到了Cookie,把session id存在Cookie中,每次访问的时候将Session ID带过去就可以识别了。
  • 大白话:当你一次访问服务器的时候,服务器会在内存中开辟一块空间,返回唯一一把打开该空间的钥匙,再把这把钥匙返回到浏览器。
    当你第二次访问的时候浏览器会携带这把钥匙到服务器端打开对应的空间,如果该空间已经销毁又重新返回开辟一块新的空间返回新的钥匙到浏览器。

区别

  • 存储数据量方面:session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象。
  • 一个在客户端一个在服务端。因Cookie在客户端所以可以编辑伪造,不是十分安全。
  • Session过多时会消耗服务器资源,大型网站会有专门Session服务器,Cookie存在客户端没问题。
  • 域的支持范围不一样,比方说a.com的Cookie在a.com下都能用,而www.a.com的Session在api.a.com下都不能用,解决这个问题的办法是JSONP或者跨域资源共享。

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中

session多服务器间共享

  1. 服务器实现的 session 复制或 session 共享,如 webSphere或 JBOSS 在搭集群时配置实现 session
    复制或 session 共享.致命缺点:不好扩展和移植。
  2. 利用成熟技术做session复制,如12306使用的gemfire,如常见内存数据库redis或memorycache,虽较普适但依赖第三方。
  3. 将 session维护在客户端,利用 cookie,但客户端存在风险数据不安全,且可以存放的数据量较小,所以将session维护在客户端还要对 session 中的信息加密。
  4. 第二种方案和第三种方案的合体,可用gemfire实现 session 复制共享,还可将session 维护在 redis中实现session 共享,同时可将 session 维护在客户端的cookie 中,但前提是数据要加密。

这三种方式可迅速切换,而不影响应用正常执行。在实践中,首选 gemfire 或者 redis 作为 session 共享的载体,一旦 session 不稳定出现问题的时候,可以紧急切换 cookie 维护 session 作为备用,不影响应用提供服务。

单点登录中,cookie 被禁用了怎么办?(一点登陆,子网站其他系统不用再登陆)

  • 单点登录的原理是后端生成一个 session ID,设置到cookie,后面所有请求浏览器都会带上cookie,然后服务端从cookie获取 session ID,查询到用户信息。
  • 所以,保持登录的关键不是cookie,而是通过cookie 保存和传输的 session ID,本质是能获取用户信息的数据。
  • 除了cookie,还常用 HTTP 请求头来传输。但这个请求头浏览器不会像cookie一样自动携带,需手工处理。

十二、SQL 注入

SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

12.1、SQL注入攻击的总体思路

  • 寻找到SQL注入的位置
  • 判断服务器类型和后台数据库类型
  • 针对不通的服务器和数据库特点进行SQL注入攻击

12.2、SQL注入攻击实例

比如,在一个登录界面,要求输入用户名和密码,可以这样输入实现免帐号登录:

用户名: ‘or 1 = 1 --
密 码:

用户一旦点击登录,如若没有做特殊处理,那么这个非法用户就很得意的登陆进去了。这是为什么呢?下面我们分析一下:从理论上说,后台认证程序中会有如下的SQL语句:String sql = “select * from user_table where username=’ “+userName+” ’ and password=’ “+password+” ‘”; 因此,当输入了上面的用户名和密码,上面的SQL语句变成:SELECT * FROM user_table WHERE username=’’or 1 = 1 – and password=’’。分析上述SQL语句我们知道, username=‘ or 1=1 这个语句一定会成功;然后后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用。这样,上述语句永远都能正确执行,用户轻易骗过系统,获取合法身份。

12.3、应对方法

  • 参数绑定
    使用预编译手段,绑定参数是最好的防SQL注入的方法。目前许多的ORM框架及JDBC等都实现了SQL预编译和参数绑定功能,攻击者的恶意SQL会被当做SQL的参数而不是SQL命令被执行。在mybatis的mapper文件中,对于传递的参数我们一般是使用#和KaTeX parse error: Expected 'EOF', got '#' at position 11: 来获取参数值。当使用#̲时,变量是占位符,就是一般我们…时,变量就是直接追加在sql中,一般会有sql注入问题。

  • 使用正则表达式过滤传入的参数

十三、TCP和UDP分别对应的常见应用层协议

13.1、TCP对应的应用层协议

  • FTP:定义了文件传输协议,使用21端口。常说某某计算机开了FTP服务便是启动了文件传输服务。下载文件,上传主页,都要用到FTP服务。
  • Telnet:它是一种用于远程登陆的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。如以前的BBS是-纯字符界面的,支持BBS的服务器将23端口打开,对外提供服务。
  • SMTP:定义了简单邮件传送协议,现在很多邮件服务器都用的是这个协议,用于发送邮件。如常见的免费邮件服务中用的就是这个邮件服务端口,所以在电子邮件设置-中常看到有这么SMTP端口设置这个栏,服务器开放的是25号端口。
  • POP3:它是和SMTP对应,POP3用于接收邮件。通常情况下,POP3协议所用的是110端口。也是说,只要你有相应的使用POP3协议的程序(例如Fo-xmail或Outlook),就可以不以Web方式登陆进邮箱界面,直接用邮件程序就可以收到邮件(如是163邮箱就没有必要先进入网易网站,再进入自己的邮-箱来收信)。
  • HTTP:从Web服务器传输超文本到本地浏览器的传送协议。

13.2、 UDP对应的应用层协议

  • DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。
  • SNMP:简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。
  • TFTP(Trival File Transfer Protocal):简单文件传输协议,该协议在熟知端口69上使用UDP服务。

十四、网络层的ARP协议(地址解析协议)工作原理

网络层的ARP协议完成了IP地址与物理地址的映射。

  • 首先,每台主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址的对应关系。
  • 当源主机需要将一个数据包要发送到目的主机时,会首先检查自己ARP列表中是否存在该IP地址对应的MAC地址:如果有,就直接将数据包发送到这个MAC地址;
  • 如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。
  • 此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。
  • 如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个ARP响应数据包,告诉对方自己是它需要查找的MAC地址;
  • 源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。
  • 如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。

十五、 常见状态码及原因短语

  • HTTP请求结构: 请求方式 + 请求URI + 协议及其版本
  • HTTP响应结构: 状态码 + 原因短语 + 协议及其版本

1×× : 请求处理中,请求已被接受,正在处理

2×× : 请求成功,请求被成功处理

  • 200 OK

3×× : 重定向,要完成请求必须进行进一步处理

  • 301 : 永久性转移
  • 302 :暂时性转移
  • 304 : 已缓存

4×× : 客户端错误,请求不合法

  • 400:Bad Request,请求有语法问题
  • 403:拒绝请求
  • 404:客户端所访问的页面不存在

5×× : 服务器端错误,服务器不能处理合法请求

  • 500 :服务器内部错误
  • 503 : 服务不可用,稍等

十六、DHCP(Dynamic Host Configuration Protocol):动态主机配置协议

在常见的小型网络中(例如家庭网络和学生宿舍网),网络管理员都是采用手工分配IP地址的方法,而到了中、大型网络,这种方法就不太适用了。在中、大型网络,特别是大型网络中,往往有超过100台的客户机,手动分配IP地址的方法就不太合适了。因此,我们必须引入一种高效的IP地址分配方法,幸好,DHCP(Dynamic Host Configuration Protocol)为我们解决了这一难题。

DHCP的优缺点

DHCP服务优点不少:网络管理员可以验证IP地址和其它配置参数,而不用去检查每个主机;DHCP不会同时租借相同的IP地址给两台主机;DHCP管理员可以约束特定的计算机使用特定的IP地址;可以为每个DHCP作用域设置很多选项;客户机在不同子网间移动时不需要重新设置IP地址。

但同时也存在不少缺点:DHCP不能发现网络上非DHCP客户机已经在使用的IP地址;当网络上存在多个DHCP服务器时,一个DHCP服务器不能查出已被其它服务器租出去的IP地址;DHCP服务器不能跨路由器与客户机通信,除非路由器允许BOOTP转发。

工作流程

DHCP服务的工作过程是这样的:

  1. 发现阶段,即DHCP客户机寻找DHCP服务器的阶段。DHCP客户机以广播方式(因为DHCP服务器的IP地址对于客户机来说是未知的)发送DHCP discover发现信息来寻找DHCP服务器,即向地址255.255.255.255发送特定的广播信息。网络上每一台安装了TCP/IP协议的主机都会接收到这种广播信息,但只有DHCP服务器才会做出响应。

    在这里插入图片描述

  2. 提供阶段,即DHCP服务器提供IP地址的阶段。在网络中接收到DHCP discover发现信息的DHCP服务器都会做出响应,它从尚未出租的IP地址中挑选一个分配给DHCP客户机,向DHCP客户机发送一个包含出租的IP地址和其他设置的DHCP offer提供信息。

    在这里插入图片描述

  3. 选择阶段,即DHCP客户机选择某台DHCP服务器提供的IP地址的阶段。如果有多台DHCP服务器向DHCP客户机发来的DHCP offer提供信息,则DHCP客户机只接受第一个收到的DHCP offer提供信息,然后它就以广播方式回答一个DHCP request请求信息,该信息中包含向它所选定的DHCP服务器请求IP地址的内容。之所以要以广播方式回答,是为了通知所有的DHCP服务器,他将选择某台DHCP服务器所提供的IP地址。
    在这里插入图片描述

  4. 确认阶段,即DHCP服务器确认所提供的IP地址的阶段。当DHCP服务器收到DHCP客户机回答的DHCP request请求信息之后,它便向DHCP客户机发送一个包含它所提供的IP地址和其他设置的DHCP ack确认信息,告诉DHCP客户机可以使用它所提供的IP地址。然后DHCP客户机便将其TCP/IP协议与网卡绑定,另外,除DHCP客户机选中的服务器外,其他的DHCP服务器都将收回曾提供的IP地址。
    在这里插入图片描述

  5. 重新登录。以后DHCP客户机每次重新登录网络时,就不需要再发送DHCP discover发现信息了,而是直接发送包含前一次所分配的IP地址的DHCP request请求信息。当DHCP服务器收到这一信息后,它会尝试让DHCP客户机继续使用原来的IP地址,并回答一个DHCP ack确认信息。如果此IP地址已无法再分配给原来的DHCP客户机使用时(比如此IP地址已分配给其它DHCP客户机使用),则DHCP服务器给DHCP客户机回答一个DHCP nack否认信息。当原来的DHCP客户机收到此DHCP nack否认信息后,它就必须重新发送DHCP discover发现信息来请求新的IP地址。

  6. 更新租约。DHCP服务器向DHCP客户机出租的IP地址一般都有一个租借期限,期满后DHCP服务器便会收回出租的IP地址。如果DHCP客户机要延长其IP租约,则必须更新其IP租约。DHCP客户机启动时和IP租约期限过一半时,DHCP客户机都会自动向DHCP服务器发送更新其IP租约的信息。

为了便于理解,我们把DHCP客户机比做餐馆里的客人,DHCP服务器比做服务员(一个餐馆里也可以有多个服务员),IP地址比做客户需要的食物。那么可以这样描述整个过程:客人走进餐馆,问:“有没有服务员啊?”(DHCP discover),多个服务员同时回答:“有,我这有鸡翅”“有,我这有汉堡”(DHCP offer)。客人说:“好吧,我要一份汉堡”(DHCP request,这个客人比较死板,总是选择第一次听到的食物),端着汉堡的服务员回应了一声:“来啦”(DHCP ack),并把食物端到客人面前,供其享用(将网卡和IP地址绑定)。客人下次来的时候,就直接找上次那个服务员点自己喜欢的汉堡了(DHCP request),如果还有汉堡,服务员会再次确认并上菜(DHCP ack),而如果已经卖完了,服务员则会告诉客人:“不好意思,已经卖完了”(DHCP nack)。当然,服务员隔一段时间会来收拾一次桌子,除非客人特别说明这菜还要继续吃的,服务员会将剩菜端走。

DHCP CLIENT的行为

所有支持DHCP 协议并能够发起DHCP过程的终端都称之为DHCP CLIENT,包括普通PC机,各种特殊设备,如CABLE MODEM,IDT等。DHCP CLIENT自己必须能够发出DHCPDISCOVER,DHCPREQUEST,DHCPDECLINE等报文(DHCPINFORM报文也是DHCP CLIENT发出但实际中很少见),并且必须能够处理从服务器收到的以下几种报文:DHCPOFFER,DHCPACK和DHCPNAK。
在这里插入图片描述
在这里插入图片描述
如果客户通过别的手段获得了网络地址,它可以使用DHCPINFORM请求获得其它配置参数,服务器接收到DHCPINFORM包,并建立一个DHCPACK消息,在其中包括一些合适客户的配置参数,只是不包括分配网络地址,检查现有的绑定,在信息中不填充’yiaddr’字段或租用时间参数。服务器取得DHCPINFORM包内的’ciaddr’地址,而返回DHCPACK包。

DHCPDECLINE ——客户机通知服务器,其分配的地址已经被其他设置。

十七、HTTP 方法:GET 对比 POST

在这里插入图片描述
在这里插入图片描述

十八、Socket

  • Socket就是为网络服务提供的一种机制。
  • 通信的两端都有Socket。
  • 网络通信其实就是Socket间的通信。
  • 数据在两个Socket间通过IO传输。
  • 玩Socket主要就是记住流程,代码查文档就行。

18.1、UDP传输:DatagramSocket与DatagramPacket

发送端:

  • 建立DatagramSocket服务;
  • 提供数据,并将数据封装到字节数组中;
  • 创建DatagramPacket数据包,并把数据封装到包中,同时指定IP和接收端口。
  • 通过Socket服务,利用send方法将数据包发送出去。
  • 关闭DatagramSocket和DatagramPacket服务。

接收端:

  • 建立DatagramSocket服务,并监听一个端口。
  • 定义一个字节数组和一个数据包,同时将数组封装进数据包。
  • 通过DatagramPacket的receive方法,将接收的数据存入定义好的数据包。
  • 通过DatagramPacke关闭t的方法,获取发送数据包中的信息。
  • 关闭DatagramSocket和DatagramPacket服务。

DatagramSocket与DatagramPacket方法摘要:

DatagramSocket

构造方法:

DatagramSocket() 
构造数据报套接字并将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port) 
创建数据报套接字并将其绑定到本地主机上的指定端口。 
DatagramSocket(int port, InetAddress laddr) 
创建数据报套接字,将其绑定到指定的本地地址。 

方法摘要:

void close() 
关闭此数据报套接字。
InetAddress getInetAddress() 
返回此套接字连接的地址。 
InetAddress getLocalAddress() 
获取套接字绑定的本地地址。
int getPort() 
返回此套接字的端口。 
void receive(DatagramPacket p) 
从此套接字接收数据报包。 
void send(DatagramPacket p) 
从此套接字发送数据报包。
DatagramPacket

构造方法:

DatagramPacket(byte[] buf, int length) 
构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
InetAddress getAddress() 
返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。 
byte[] getData() 
返回数据缓冲区。 
int getLength() 
返回将要发送或接收到的数据的长度。
int getPort() 
返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。	

代码示例:

****发送端
class UDPSend
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket();
byte[] buf = "这是UDP发送端".getBytes();
DatagramPacket dp = new DatagramPacket(
buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
ds.send(dp);
ds.close();
}
}

****接收端
class UDPRece
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(10000);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
String data = new String(dp.getData(),0,dp.getLength());//获取数据
int port = dp.getPort();//获取发送端的端口号
sop(ip+":"+data+":"+port);
ds.close();
}
}

需求1:UDP键盘录入数据,并发送给接收端

发送端:
class UDPSend{
public static void main(String[] args) throws Exception{

DatagramSocket ds = new DatagramSocket();
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine())!=null){
if("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(
buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
ds.send(dp);
}
ds.close();
}

}
接收端:
class UDPRece{
public static void main(String[] args) throws Exception{
DatagramSocket ds = new DatagramSocket(10000);
while(true){
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
String data = new String(dp.getData(),0,dp.getLength());//获取数据
int port = dp.getPort();//获取发送端的端口号
sop(ip+":"+data+":"+port);
ds.close();
}
}
}

需求2:编写简单的聊天工具

思路:使用多线程技术

发送端:
class UDPSend implements Runnable{
private DatagramSocket ds;
public UDPSend(){}
public UDPSend(DatagramSocket ds){
this.ds=ds;
}
public void run(){
try{
BufferedReader bufr = new BufferedReader(
new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine())!=null){
if("886".equals(line))
break;
byte[] buff = line.getBytes();
DatagramPacket dp = new DatagramPacket(
buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
ds.send(dp);
}
}
catch(Exception e){
throw new RuntimeException("发送失败");
}
}
}
接收端:
class UDPRece implements Runnable{
private DatagramSocket ds;
public UDPSend(){}
public UDPSend(DatagramSocket ds){
this.ds=ds;
}
public void run(){
try
{
while(true){    
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
String data = new String(dp.getData(),0,dp.getLength());//获取数据
int port = dp.getPort();//获取发送端的端口号
sop(ip+":"+data+":"+port);    
}
}
catch(Exception e){
throw new RuntimeException("接收失败");
}
}
}
测试类:
class UDPTest
{
public static void main(String[] args)
{
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(10000);

new Thread(new UDPSend(sendSocket)).start();
new Thread(new UDPRece(receSocket)).start();
}
}

18.2、TCP传输Socket和ServerSocket

  • 建立客户端和服务器端。
  • 建立连接后,通过Socket中的IO流进行数据的传输。
  • 关闭socket。
  • 同样,客户端与服务器端是两个独立的应用程序。

Socket

构造方法:

Socket() 
通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port) 
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(String host, int port) 
创建一个流套接字并将其连接到指定主机上的指定端口号。

方法摘要:

void close() 
关闭此套接字。
InetAddress getInetAddress() 
返回套接字连接的地址。
InputStream getInputStream() 
返回此套接字的输入流。
OutputStream getOutputStream() 
返回此套接字的输出流。 
int getPort() 
返回此套接字连接到的远程端口。
void shutdownInput() 
此套接字的输入流置于“流的末尾”。 
void shutdownOutput() 
禁用此套接字的输出流。 
String toString() 
将此套接字转换为 String。

ServerSocket

构造方法:

ServerSocket() 
创建非绑定服务器套接字。 
ServerSocket(int port) 
创建绑定到特定端口的服务器套接字。
方法摘要:
Socket accept() 
侦听并接受到此套接字的连接。
void close() 
关闭此套接字。 
InetAddress getInetAddress() 
返回此服务器套接字的本地地址。

TCP传输流程:

客户端:
  • 建立Socket服务,并制定要连接的主机和端口。
  • 获取Socket流中的输出流OutputStream,将数据写入流中,通过网络发送给服务端。
  • 获取Socket流中的输出流InputStream,获取服务端的反馈信息。
  • 关闭资源。
服务端:
  • 建立ServerSocket服务,并监听一个端口。
  • 通过ServerSocket服务的accept方法,获取Socket服务对象。
  • 使用客户端对象的读取流获取客户端发送过来的数据。
  • 通过客户端对象的写入流反馈信息给客户端。
  • 关闭资源。

代码示例:

客户端:
class TCPClient
{
public static void main(String[] args)
{
Socket s = new Socket("192.168.1.253",10000);
OutputStream os = s.getOutputStream();
out.write("这是TCP发送的数据".getBytes());
s.close();
}
}
服务端:
class TCPServer
{
public static void main(String[] args)
{
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
sop(ip);

InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
sop(new String(buf,0,len));
s.close();
ss.close();
}
}

TCP需求1:客户端给服务端发送数据,服务端接收到后反馈信息给客户端。

客户端:
class TCPClient
{
public static void main(String[] args)
{
Socket s = new Socket("192.168.1.253",10000);
OutputStream os = s.getOutputStream();
out.write("这是TCP发送的数据".getBytes());

InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
sop(new String(buf,0,len));
s.close();
}
}
服务端:
class TCPServer
{
public static void main(String[] args)
{
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
sop(ip);

InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
sop(new String(buf,0,len));

OutputStream os = s.getOutputStream();
out.write("这是TCP发送的数据".getBytes());

s.close();
ss.close();
}
}

TCP需求2:建立一个文本转换服务端,客户给服务端发送文本,服务端将数据转换成大写后返回给客户端,当客户端输入over时,转换结束。

客户端:
class TCPClient
{
public static void main(String[] args)
{
Socket s = new Socket("192.168.1.253",10000);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String line = null;
while((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufOut.write(line);
bufOut.newLine();
bufOut.flush();
String retVal = bufIn.readLine();
sop("server:"+retVal);
}
bufr.close();
s.close();
}
}
服务端:
class TCPServer
{
public static void main(String[] args)
{
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
sop(ip);

BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));

while((line = bufIn.readLine())!=null)
{
bufOut.write(line.toUpperCase());
bufOut.newLine();
bufOut.flush();
}
s.close();
ss.close();
}
}

需求3:拷贝文件

客户端:
class TCPClient
{
public static void main(String[] args)
{
Socket s = new Socket("192.168.1.253",10000);
BufferedReader bufr = new BufferedReader(new FileReader("g:\\demo.txt"));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line = bufr.readLine())!=null)
{
pw.println();
}
s.shutDownOutput();
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String retVal = bufIn.readLine();
sop(retVal);
bufr.close();
s.close();
}
}
服务端:
class TCPServer
{
public static void main(String[] args)
{
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
sop(ip);

BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
PrintWriter out = new PrintWriter(new FileWriter"copy.txt",true);
String line =null;
while((line = bufIn.readLine())!=null)
{
out.write(line);
}
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("上传成功");
out.close();
s.close();
ss.close();
}
}

需求4:上传图片

客户端:
class TCPClient
{
public static void main(String[] args)
{
Socket s = new Socket("192.168.1.253",10000);
FileInputStream fis = new FileInputStream("g:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = bufr.read())!=-1)
{
out.write(buf,0,len);
}
s.shutDownOutput();

InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int lenIn = in.read(bufIn);
sop(new String(bufIn,0,lenIn);
fis.close();
s.close();
}
}
服务端:
class TCPServer
{
public static void main(String[] args)
{
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
sop(ip);
FileOutputStream fos = new FileOutputStream("g:\\copy.bmp");
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int lenIn = 0;
while((lenIn=bufIn.read())!=-1)
{
fos.write(bufIn,0,lenIn)
}

OutputStream outIn = s.getOutputStream();
outIn.write("上传成功".getBytes());
fos.close();
s.close();
ss.close();
}
}

需求5:客户端并发登陆

客户端通过键盘录入用户名,服务端对这个用户名进行校验,
如果用户存在,在服务端现实xxx已登录,并在客户端现实欢迎xxx。
如果用户不存在,在服务端现实xxx正在尝试登陆,并在客户端现实xxx用户不存在,最多登陆三次。

校验端:
class User implements Runnable
(
private Socket s;
public User(){}
public User(Socket s)
{
this.s=s;
}
public void run()
{
try
{
BufferedReader bufrIn = new BufferedReader(
new InputStream(s.getInputStream()))
String name = bufrIn.readLine();
if(name==null)
{
sop("用户名为空");
break;
}
BufferedReader bufr = new BufferedReader(
new FileReader("user.txt"));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
String line = null;
boolean flag = false;
while((line = bufr.reanLine())!=null)
{
if(line.equals(name))
{
flag = true;
break;
}
if(flag)
{
sop(name+"已登陆");
pw.println("欢迎"+name);
break;
}
else
{
sop(name+"正尝试登陆");
pw.println(name+"用户不存在");
}

}
s.close();
}
catch(Exception e)
{
throw new RuntimeException("用户校验失败");
}
}
)
客户端:
class LoginClient
{
public static void main(String[] args)
{
Socket s = new Socket("192.168.1.253",10000);
BufferedReader bufr = new BufferedReader(
new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
BufferedReader bufIn = new BufferedReader(
new InputStreamReader(s.getInputStream()));
for(int i=0;i<3;i++)
{
String line = bufr.readLine();
if(line == null)
{
sop("用户名不能为空!");
break;
}
out.write(line);
String retVal = bufIn.readLine();
sop(retVal);    
}
bufr.close();
s.close();
}
}
服务端:
class LoginServer
{
public static void main(String[] args)
{
ServerSocket ss = new ServerSocket(10000);
while(true)
{
Socket s = ss.accept();
new Thread(new User()).start();
}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值