Java网络编程精解笔记1:入门

Java网络编程精解笔记1:入门

1.Client Program       ServerProgram
   |_________ 计算机网络____________| 

 1.如张三给李四寄信,其不必亲自送到李四家里.送信任务由邮政网络完成.其只需提供李四的地址,邮政网络即可准确将的将信送达目标地址.
 2.server与client program只关心什么样的数据发送给对方,而不必考虑数据如何传输给对方.传输任务由计算机网络完成.
 3.网络应用程序建立在计算机网络的基础上.

2.进程之间的通信:

 1.java EchoPlayer,启动EchoPlayer进程,该进程执行main(启动了一个JVM进程)
 2.client-> 本地控制台->System.in,标准输入->EchoPlayer进程
         System.out,标准输出<-
 3.响应结果移到远程主机->EchoClient & EchoServer
   client->客户机控制台->EchoClient进程   --------->网络--------->远程主机服务器,EchoServer进程
                   <--------网络<--------
   1.如张三,李四通话,前提是他们的电话机投连接到电话网络.二者只关心谈话内容,而不必考虑语言如何传输到对方电话上.传输语音任务由电话网络完成.
   2.两个进程顺利通信的前提是所在主机都连接到计算机网网络上.EchoClient和EchoServer只关注通信具体内容,无需考虑如何传送给对方.传输信息的任务由计算机网络来完成.

3.计算机网络的概念

 1.通俗的讲计算机网络即通过电缆,电话线或无线通信设施等互联的计算机集合.网络中每台机器成为节点.
 2.本书节点一词指网络中任意一个设备,用主机指网络中的计算机节点.
 3.人与人之前通过某种语言来交流,网络中的主机也通过"语言交流",这样语言称为网络协议.-->通俗解释.
 4.网络中每个主机都有地址,其是用于标识主机的一个字节序列.字节序列越长,标识的地址数目就越多,更多的设备可连入网络.
 5.上海人讲上海话,广东人将广东话,上海人与广东人用普通话沟通。与此类似,不同网络之间的互联网靠网络上的标准语言-TCP/IP协议.

4.OSI参考模型

 1.计算机网络之初,每个计算机厂商都有一套自己的网络体系结构,互不相容.->ISO->OSI(Open System Interconnection)体系结构->Open一词以为一个网络系统只要遵循该模型,即可与世界上任何地方的也遵循osi模型的其他网络系统连接.
 2.osi把网络分为7层,物理层,数据链路层,网络层,传输层,会话层,表示层和应用层.每一层使用下层提供的服务并为上层提供服务.
 3.不同主机之间的相同层称为对等层.
 4.osi各层主要功能:
  1.物理层:物理介质->第0层.->为上一层提供物理连接,规定通信节点之间的机械和电器等特性,如规定电缆和接头的类型,传送信号的电压等->bit流传输->hub(集线器).
  2.数据链路层:两个相邻节点的线路->无差错以帧传输.->建立,维持和释放数据链路的连接->接收方检测所传数据有差错->通知发送方重发这一帧->switch(交换机)
  3.网络层:两个计算机之间->经过多个数据链路->多个通信子网->选择合适的网间路由和交换节点->确保数据及时传到目标主机.>将数据链路层提供的帧组成数据包->网络包头包含有逻辑地址-源主机和目标主机的网络地址->Router(路由器).
  ->两个相邻节点之间的线路成为数据链路.数据链路层负责数据链路上的数据传输->主机A到主机B的整个路径成为路由.->网络层负责合适的路由.
  4.传输层:为源主机和目标主机的会话层提供建立,维护和取消传输连接的功能->以可靠方式或者不可靠方式(数据有可能丢失或者出错)传输数据.>报文
  5.会话层:管理进程之间的会话过程.即负责简历,管理,终止进程之间的绘画.->在数据中插入校验点来实现数据的同步.
  6.表示层:数据转换,保证一个主机的应用层数据可以被另一个主机的应用层理解.->加密,解密,压缩,解压和格式转换等.
  7.应用层:确定进程之间通信的实际用途.

   1.源主机->发送数据->目标主机->由上层向下层传递->每一层给上一层传递的数据加上一个header->向下层发出->通过物理介质传输到目标主机->下层向上层传递->每一层先对数据进行处理,去掉header.->达到最上层->还原成实际数据.
   2.各个层加入的header有着不同的内容.如果网络层加入的header包括源地址和目标地址等.->传输层header包括报文类型,源端口和目标端口等,序列号和应答号等.
   3.数据链路层还会为数据加上信息尾.
   4.发送方->数据由上至下->封装->传给下层->接收方->数据由下至上->解封装->传给上层;生活中也常采用该方式.如寄信.->信->信封->写上发信人和收信人地址.->接收方->拆开信封.
   5.osi参考模型将网络层分为多个层次,每个层次分工明确.->简化网路系统设计过程.->如设计设计传输层,只需考虑如何在两个主机传送数据;设计网络层,只需考虑如何在网络上找到一条发送数据的路径了即路由.
   6.对等层之间互相通信需要遵守规则,如通信的格式和通信内容.->网络协议.
   7.osi没有具体实现方式,只不过为其他组织制定网络协议提供了参考框架.

   
5.TCP/IP参考模型

 1.OSI参考模型过于庞大和复杂,难以投入到实际运用.->TCP/IP参考模型->简化->在网络各层(除了主机-网络层)外都提供了完善的协议->TCP/IP协议集->工业标准/事实标准.
 2.4个层次:应用层->传输层->网络互联层->主机-网络层.IP协议和TCP协议时协议集中最核心的两个协议.
 3.
  1.主机网络层:TCP/IP参考模型没有提供者这一层的实现,也没有提供协议.->第三方实现的该层能为上层网络互联层提供访问接口->传递IP数据包->IEEE802.3(以太网)->IEEE802.4(令牌环网)
  
  2.网络互联层:把IP数据包发送到目标主机->将原始数据分发成多个数据包,沿不同的路径同时传递数据包(为了尽快的发送数据)->数据包达到的顺序和发送的先后顺序可能不同->需要上层传输层对数据包重新排序,还原为原始数据.
  该层具有连接异构网的功能.如以太网和令牌环网,二者都向网络互联层提供了统一非访问接口,访问接口向上层隐藏了下层网络的差异,使得两个网络之间可以顺利传递数据包。
  采用IP协议,其规定了数据包的格式,并规定了为数据包寻找路由的流程.
  
  3.传输层:使源主机和目标主机上的进程可以进行会话.
   1.TCP:传输控制协议.面向连接,可靠.将源主机的字节流无差错的发送给互联网的目标主机.发送端将上层传下来的数据分成报文段传递给下层->接收端将受到的报文进行重组后递给上层->处理端到端的流量控制,避免接收速度慢的接收方没有足够的缓冲区来接收发送方发送的大量数据.
   2.UDP:用户数据包协议.->不可靠,无连接.适用于不需要对报文进行排序和流量控制的场合.不能保证数据包的接收顺序和发送顺序一致,甚至不能保证是否全部达到目标主机.
   
  4.应用层:
   将osi参考模型的会话层和表示层功能合并到应用层.
  基于TCP:
   1.FTP:文本传输协议,网络上传输文件
   2.TELNET:虚拟终端协议.允许从主机A登陆到远程主机B,使得主机允许充当远程主机B的虚拟终端
   3.HTTP:超文本传输协议,允许传送超文本
   4.HTTPS:安全超文本传输协议.数据加密->解密
   POP3,IMAP4,SMTP...
  基于UDP:
   SNMP,DNS
   
6.IP协议

 1.IP网络,即在网络层采用IP协议的网络中每台主机都一个唯一的ip地址,用来标识网络中的每个主机.->32位的二进制数序列.->32位分为4个单元,每个单元占8位,十进制数标识每个单元(这样就很方便表示了).->10进制数的取值范围是0-255.
  如192.168.3.4
 ->新的IPV6标准将采用128位的地址,大大扩充了可用地址的数目.
 2.IP地址由两部分组成:IP网址和IP主机地址.
  1.IP网址表示网络的地址,IP主机地址表示网络中的主机的地址.->网络掩码用来确认IP地址中哪部分是网址,哪部分是主机地址.
  2.网络掩码的限制是前部分都为1,后部分为0.
   如假定192.168.3.4的网络掩码是255.255.255.0->则用该掩码与IP地址进行二进制与操作->得到的结果就是IP网址->192.168.3.4的网址是192.168.3.0->网络掩码变为255.255.0.0则IP网址则为192.168.0.0.
  3.每个网络都有IP网址,两个网络之前用路由器连接.
   网络A          <->路由器        网络B
  网址:192.168.3.0                 网址:192.168.4.0
  掩码: 255.255.255.0                掩码: 255.255.255.0
  
  主机A:192.168.3.4                 主机C:192.168.4.4 
  主机B:192.168.3.5                 主机D:192.168.4.5 
  4.子网划分:
   1.一个公司可能有一个网址和多个主机。如网址为192.166.0.0,则可以有2¹6 - 1个主机加入网中.
   2.更好的管理网路->可将网路划分为多个子网.如划分出192.166.1.0,192.166.2.0,192.166.3.0 3个网址.掩码都为255.255.255.0.
   3.192.166.0.0和192.166.1111.1111有特殊用途,不能作为网络中的主机地址,前者是网络地址,后者是广播地址.(?广播地址应该是192.166.255.255吧?应该是8个1吧)
  5.发送数据包过程:
   1.IP面向包->数据被分成若干个小数据包->分别传输
   2.IP网络上的主机只能向本地网上的其他主机,也就是具有相同IP网址的主机们发送数据包
   3.主机实际上有两个不同性质的地址:物理地址和IP地址.物理地址是有主机的网卡标识的.物理地址才主机的真实地址.
   4.主机A向同一个网络的另一个主机发包时,会通过地址解析ARP获得对方的物理地址,然后把包发给对方.
    a.主机A在网络上广播一个ARP消息,要寻找地址为192.168.3.5的主机
    b.具有这个ip地址的主机B就会做出响应,把自身的物理地址告诉主机A.
    (同一个网络中,主机A直接向主机B发送IP数据包)

   5.主机A向另一个网络的主机B发送数据包时,主机A利用ARP协议找到本地网络的路由器的物理地址,把包转发给它.路由器处理步骤:
    1.如果数据包的生命周期已到,则数据包被抛弃.
    2.搜索路由表,优先搜索路由表中的主机,如果能找到具有目标IP地址的主机,则将数据包发送给给主机.
    3.匹配主机失败,继续所有路由表,匹配同子网的路由器.如果找到匹配的路由器,则将数据包转发给该路由器.
    4.匹配同子网的路由器失败,则继续搜索路由表,匹配同网络的路由器,如果找到,则转发给该路由.
    5.如果以上匹配都失败,则搜索默认路由.如果默认路由存在,则按默认路由发送数据包,否则丢弃.
   ->从路由器的处理步骤,IP协议并不保证一定把数据包送达目标主机.在发送过程汇总,会因为数据包结束生命周期,或者找不到路由而丢弃数据包.
  6.域名
   1.IP地址和域名一一对应.(字符型,记忆方便)
   2.从右至左表述意义.最右->顶层域;做左->主机的机器名称;->主机机器名.单位名.网络名.顶层域名. mail.xyz.edu.cn
   3.DNS->采用DNS服务器提供把域名转换为IP地址.
   4.URL:统一资源定位器,标识网络上资源位置而设的一种编码方式.
    应用层协议://主机IP地址或域名/资源所在路径/文件名 http://www.javathinker.org/bbs/index.jsp
    常见的应用层协议还包括ftp和file.
    ftp://www.javathinker.org/image
    file:///C:\atomcat\webappes\javathinker\admin.jsp
    file协议用于访问本地计算机上的文件,使用这种协议的URL以"file:///"
    
7.TCP协议及端口

 1.Ip协议在发送数据包时->路由器突然崩溃->包丢失|一个包沿低速链路,另一个包沿高速链路而超过前面的包->包的顺序搞乱.
 2.TCP协议使得两台主机的进程顺利通信->不必担心包丢失或顺序搞乱->TCP根据包顺序,并且在包顺序搞乱时按正确顺序重组包->包丢失则会请求源主机重发包.
 3.主机A的A1进程向主机B的B1进程发送数据.IP协议根据主机B的ip地址,把A1发送的数据送达主机B->TCP决定把数据发送到主机B的哪个进程->TCP采用端口来表示进程.->表示进程的逻辑地址->表示TCP连接的端点的逻辑地址.
 ->两个进程进行一次通信,就意味建立了一个TCP连接.->B:80->A:1000
 ->每个进程有唯一的地址,TCP就能保证把数据顺利送到特定的进程.
 ->注:只有进程通信的时候采用有端口的概念.
 ->TCP采用端口来区分进程间的通信
 4.C/S模型中,client进程可能与服务器进程简历多个TCP连接.在client端,每一个TCP连接都会分配一个端口.
 5.端口号->0-65535.0-1023的端口号固定分配给一些服务.21-FTP,25-SMTP,80-HTTP,135-RPC;1024到65535的端口号供用户自定义的服务使用.->如EchoServer服务使用8000端口,该程序运行时,就会占用8000端口.程序结束时,就会释放所占用的端口.
 6.客户端进程的端口一般由主机的os动态分配->客户进程要求与一个服务器进程进行TCP连接时,os会为客户端进程随机分配一个还未被占用的端口.当client进程与server进程断开连接时,这个端口就被释放.
 7.TCP和UDP都用端口来标识进程的.在一个主机中,二者端口的取值范围是各自独立的.即允许存在取值相同的TCP端口与UDP端口.
  如进程A1占用Ftp端口1000,进程A2占用UDP端口1000.->这是允许的.
  
8.RFC

 1.TCP/IP协议是以RFC(Request For Comment)文档形式发布的.RFC是描述互联网相关技术规范的文档.
 2.每一个文档有一个RFC编号.
 3.http://www.ietf.org/rfc.html
 4.输入http://www.ietf.org/rfc/rfcXXXX.txt.就能查看相关的RFC文档,XXX表示文档编号.如FTP协议的RFC文档的网址为
  http://www.ietf.org/rfc/rfc959.txt
 5.文档一旦发布,其编号和内容就不允许改变.如果需要更新,则会对更新后的RFC文档赋予新的编号.
 
9.C/S通信模式
 1.C/S.一个进程为客户进程,一个进程为服务器进程.->client->request->server->response.
 2.一个服务器进程会同时为多个客户进程服务.
 3.服务器进程大致工作流程:
  while(true)
  {
   监听端口,等待客户请求;
   响应客户请求;
  }
 4.EchoServer,用户自定义的服务.->还有许多通用服务,如HTTP服务->网络应用层的协议规定了客户程序与这些通用服务器程序的通信细节.->如规定了Http客户程序所发出的请求的格式.还规定了HTTP服务器程序发回的响应的格式.
 5.现实中,某些重要的服务机构的电话是固定的,如110,方便人们记住电话和获得服务.同样网络上有些通用的服务用着固定的端口.
  FTP 21;TELNET 23;SMTP 25;HTTP 80;POP3 110;IMAP4 143;HTTPS 443;TELNETS 992;IMAPS 993;
  
10.Java编写C/S程序

 1.本书的Java网络程序都建立在TCP/IP协议基础上,致力于实现应用层.
 2.传输层向应用层提供了套接字Socket接口.Socket封装了下层的数据传输细节->应用层的程序通过Socket来简历与远程主机的连接以及进行数据传输.
 3.应用层的角度,两个进程之间的一次通信过程从建立连接开始->接着交换数据->到断开连接结束->套接字可看做是通信线路两端的收发器,进程通过套接字来收发数据.
 进程A1-Socket<---TCP连接--->Socket-进程B1
 4.Java中有3中套接字类:Socket/ServerSocket/DatagramSocket.前2建立在TCP协议基础上,3建立在UDP协议基础上.->Java网络程序都采用C/S通信模式.

部分源代码

package  com.game.landon.entrance;

import  java.io.BufferedReader;
import  java.io.IOException;
import  java.io.InputStreamReader;

/** */ /**
 *
 *从控制台读取输入字符串,并echo:XX
 *<p>输入bye,则结束程序</p>
 *
 *
@author landon
 *
@since 1.6.0_35
 *
@version 1.0.0 2013-5-27
 *
 
*/


public   class  EchoPlayer
{
    
public String echo(String msg)
    
{
        
return "echo:" + msg;
    }

    
    
public void talk() throws IOException
    
{
        BufferedReader br 
= new BufferedReader(new InputStreamReader(System.in));
        String msg 
= null;
        
        
while((msg = br.readLine()) != null)
        
{
            System.out.println(echo(msg));
            
            
if("bye".equals(msg))
            
{
                
break;
            }

        }

    }

    
    
public static void main(String[] args) throws IOException
    
{
        EchoPlayer echoPlayer 
= new EchoPlayer();
        echoPlayer.talk();
    }

}

 

package  com.game.landon.entrance;

import  java.io.BufferedReader;
import  java.io.IOException;
import  java.io.InputStream;
import  java.io.InputStreamReader;
import  java.io.OutputStream;
import  java.io.PrintWriter;
import  java.net.Socket;

/** */ /**
 *
 *A Easy Echo Client
 *
 *
@author landon
 *
@since 1.6.0_35
 *
@version 1.0.0 2012-9-27
 *
 
*/


public   class  EchoClient
{
    
private String host = "localhost";
    
private int port = 8000;
    
private Socket socket;
    
    
public EchoClient() throws IOException
    
{
        
//connect to the server with specified host and port 
        
//os为客户的每个连接分配一个唯一的端口
        
//客户进程中,Socket对象包含了本地及对方服务进程的端口信息.在服务器进程中,Socket对象也包含了本地以及对方客户进程的地址和端口信息.
        
//客户进程允许建立多个连接,每个连接都有唯一的端口
        
//编写网络程序时,一般只需显示的为服务器程序中的ServerSocket设置端口,而不必考虑客户程序所用的端口
        socket = new Socket(host,port);
    }

    
    
/** *//**
     * Wrapped {
@link Socket#getOutputStream()} to PrintWriter
     * 
@param socket
     * 
@return
     * 
@throws IOException
     
*/

    
private PrintWriter getWriter(Socket socket) throws IOException
    
{
        OutputStream socketOut 
= socket.getOutputStream();
        
//public PrintWriter(OutputStream out, boolean autoFlush)
        return new PrintWriter(socketOut,true);
    }

    
    
/** *//**
     * Wrapped {
@link Socket#getInputStream()} to BufferedReader
     * 
@param socket
     * 
@return
     * 
@throws IOException
     
*/

    
private BufferedReader getReader(Socket socket) throws IOException
    
{
        InputStream socketIn 
= socket.getInputStream();
        
return new BufferedReader(new InputStreamReader(socketIn));
    }

    
    
/** *//**
     * 
     * talk to echo server
     * 
     * 
@throws IOException
     
*/

    
public void talk() throws IOException
    
{
        
try
        
{
            
//与Echo Server通信用的到包装后的reader和writer
            BufferedReader br = getReader(socket);
            PrintWriter pw 
= getWriter(socket);
            
            
//本地reader,用来从system.in,即控制台输入数据
            BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
            String msg 
= null;
            
            
while((msg = localReader.readLine()) != null)
            
{
                
//向server输出消息
                pw.println(msg);
                
//从server读取消息
                System.out.println(br.readLine());
                
                
if("bye".equals(msg))
                
{
                    
break;
                }

            }

        }

        
catch(IOException e)
        
{
            e.printStackTrace();
        }

        
finally
        
{
            
try
            
{
                socket.close();
            }

            
catch(IOException e)
            
{
                e.printStackTrace();
            }

        }

    }

    
    
public static void main(Stringargs) throws IOException
    
{
        
new EchoClient().talk();
    }

}

 

package  com.game.landon.entrance;

import  java.io.BufferedReader;
import  java.io.IOException;
import  java.io.InputStream;
import  java.io.InputStreamReader;
import  java.io.OutputStream;
import  java.io.PrintWriter;
import  java.net.ServerSocket;
import  java.net.Socket;

/** */ /**
 *
 *A Easy Echo Server
 *<p>
 *1.当前这个EchoServer的问题是只能连接一个Client,只有当前的client输入bye,结束连接的时候,才会处理下一个client
 *2.原因在于service方法,while(br.readLine() != null),这里,当Client没有输入数据时,线程则挂起,阻塞,等待client输入
 *</p>
 *
 *
@author landon
 *
@since 1.6.0_35
 *
@version 1.0.0 2012-9-27
 *
 
*/


public   class  EchoServer
{
    
private int port  = 8000;
    
private ServerSocket serverSocket;
    
    
public EchoServer() throws IOException
    
{
        
//ServerSocket
        
// 构造方法负责在os中把当前进程注册为服务器进程,监听port端口
        serverSocket = new ServerSocket(port);
        System.out.println(
"Echo Server Launched!");
    }

    
    
/** *//**
     * echo to client
     * 
@param msg
     * 
@return
     
*/

    
public String echo(String msg)
    
{
        
return "echo:" + msg;
    }

    
    
/** *//**
     * Wrapped {
@link Socket#getOutputStream()} to PrintWriter
     * 
@param socket
     * 
@return
     * 
@throws IOException
     
*/

    
private PrintWriter getWriter(Socket socket) throws IOException
    
{
        
// 返回输出流对象,向输出流写数据,就能向对方发送数据
        OutputStream socketOut = socket.getOutputStream();
        
//public PrintWriter(OutputStream out, boolean autoFlush)
        return new PrintWriter(socketOut,true);
    }

    
    
/** *//**
     * Wrapped {
@link Socket#getInputStream()} to BufferedReader
     * 
@param socket
     * 
@return
     * 
@throws IOException
     
*/

    
private BufferedReader getReader(Socket socket) throws IOException
    
{
        
// 返回输入流对象;只需从输入流读数据,就能接收来自对方的数据
        InputStream socketIn = socket.getInputStream();
        
return new BufferedReader(new InputStreamReader(socketIn));
    }

    
    
/** *//**
     * Echo Server main Logic Service
     
*/

    
public void service()
    
{
        
//while true loop to wait client connect
        while(true)
        
{
            Socket socket 
= null;
            
try
            
{
                
//accept client socket
                
// 监听端口,等待客户的连接请求,如果接收到一个连接请求,该方法返回一个Socket对象.该Socket对象与客户端的Socket对象形成了一条通信线路
                
//该Socket对象包含了客户的地址和端口信息.EchoClient作为客户程序,它的端口是由os随机产生的.每当客户程序创建一个Socket对象时,os就会客户分配一个端口
                socket = serverSocket.accept();
                System.out.println(
"New Connection accepted:" + socket.getInetAddress() + ":" + socket.getPort());
                
                BufferedReader br 
= getReader(socket);
                PrintWriter pw 
= getWriter(socket);
                
                String msg 
= null;
                
//read from client
                while((msg = br.readLine()) != null)
                
{
                    System.out.println(msg);
                    
//write to client
                    pw.println(echo(msg));
                    
                    
if(msg.equals("bye"))
                    
{
                        
break;
                    }

                }

            }

            
catch(IOException e)
            
{
                e.printStackTrace();
            }

            
finally
            
{
                
try
                
{
                    
if(socket != null)
                    
{
                        
//close socket
                        socket.close();
                    }

                }

                
catch(IOException e)
                
{
                    e.printStackTrace();
                }

            }

        }

    }

    
    
public static void main(Stringargs) throws IOException
    
{
        
//launch echo_server
        new EchoServer().service();
    }

}


 

你可能感兴趣的:(Java网络编程精解笔记1:入门)