网络编程

第一  概述

一、概述:

1、网络模型:OSI参考模型和TCP/IP参考模型

 

2、网络通讯要素:

1)IP地址:InetAddress

   .网络中设备的标识
   .不易记忆,可用主机名

Internet上的主机有两种方式表示地址:域名:www.baidu.com,IP 地址:202.108.35.210 

InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址:www.baidu.com。域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。 
2)端口号
.用于标识进程的逻辑地址,不同进程的标识
.有效地址0~65535,其中0~1024系统使用或保留端口
3)传输协议:
通讯规则
    .常见协议:TCP、UDP

①UDP(面向无连接)-->聊天、网络视频会议、步话机

 

  •  将数据及源和目的封装成数据包中,不需要建立连接
  • .每个数据包的大小限制在64k内
  • .因无连接,是不可靠的协议
  • .不需要建立连接,速度快

 

②TCP(面向连接)-->下载,打电话

 

  • 建立连接,形成传输数据的通道
  • 在连接中进行大数据量的传输
  • 通过三次握手完成连接,是可靠的协议
  • .必须建立连接,效率会稍低

 

注:三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方再次发送确认信息告诉对方,这样双方就都知道了,从而才能建立连接

 

3、通信的步骤:

1)IP:找到需要通讯的IP地址

2)端口:数据要发送到对象指定应用程序,为标识这些应用程序,所以给这些网络应用程序都用数字标识,为方便称呼这个数字,叫做端口,即逻辑端口。每个网络程序都有自己唯一的标识端口。

3)定义通信规则,称之为协议。国际组织定义了通用协议,即TCP/IP。

注意:必须要有数字标识才能将数据发送到应用程序上。因为端口是明确数据需要有哪个应用程序来处理的标识。

 

二、网络模型:

1、对于TCP/IP协议,开发处于传输层和网际层

      应用层:FTP和HTTP协议等

      传输层:UDP和TCP等

      网际层:IP

三、网络通信要素:

IP地址:java中对应的是InetAddress类,存在于java.net包中。

InetAddress类:

1、无构造函数,可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回此对象。

       InetAddress i = InetAddress.getLocalHost();

2、方法:

1)static InetAddress getByName(String host):在给定主机名的情况下获取主机的IP地址

2)String getHostAddress():返回IP地址字符串文本形式,以这个为主,即以IP地址为主。

3)String getHostName():返回IP地址主机名。

3、如何获取任意一台主机的IP地址对象:
  1. publicclassIPDemo{
  2. publicstaticvoid main(String[] args)throwsUnknownHostException{
  3. // 获取本地主机ip地址对象。
  4. InetAddress ip =InetAddress.getLocalHost();
  5. System.out.println(ip.getHostAddress());//192.168.1.167
  6. System.out.println(ip.getHostName());//PC201508162051
  7. // // 获取其他主机的ip地址对象。只要输入iP或域名
  8. InetAddress byName =InetAddress.getByName("PC201508162051");// PC201508162051/192.168.1.167
  9. InetAddress byName2 =InetAddress.getByName("www.baidu.com");// www.baidu.com/61.135.169.121
  10. System.out.println(byName);
  11. System.out.println(byName2);

  12. }
  13. }

第二  UDP

一、概述:

Socket:

 

  1. Socket就是为网络服务提供的一种机制
  2. 通讯的两端都必须有Socket(套接字),相当于港口
  3. 网络通讯其实就是Socket间的通讯
  4. 数据在两个Socket间通过IO传输
  5. IP 地址标识 Internet 上的计算机,端口号标识正在计算机上运行的进程(程序)。端口号与IP地址的组合得出一个网络套接字。

 

二、UDP传输:发送端和接收端是两个独立运行的程序

1、UDP传输的流程:

 

  • .DatagramSocke(创建Socket对象在发送端和接收端通讯)和DatagramPacket(发送端将数据封包,接收端将数据解包)
  • .建立发送端、接收端
  • .建立数据包
  • .调用Socket的发送和接收方法
  • .关闭Socket

 

 

 

DatagramPacket(byte[] buf, int length)接收
          构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)发送
          构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

 

2、方法:

 

  • 创建 UDPSocket发送服务对象:DatagramSocket(),可不指定端口
  • 创建 UDPSocket接收服务对象:DatagramSocket(int port),
  • 发送:void send(DatagramPacket p)
  • 接收:void receive(DatagramPacket p)

 

其中DatagramPacket:数据报包用来实现无连接包投递服务的,每条报文仅根据该包中包含的信息从一台机器路由到另一台机器中。

凡是带地址(InetAddress)的都是用于发送包的。

实例:

  1. /*
  2. * 需求:通过udp传输方式,将一段文字发送出去
  3. * 定义一个udp发送端
  4. */
  5. publicclassUDPSend{
  6. publicstaticvoid main(String[] args)throwsSocketException,Exception{
  7. // 1、建立udp服务,通过DategramSocket对象
  8.  
  9. DatagramSocket ds =newDatagramSocket(8888);
  10. // 2、确定数据,并封装成数据包DatagramPacket(byte[] buf, int length, InetAddress,address, int port)
  11. byte[] buf ="udp send message come on".getBytes();// 数据 ,转成字节数组
  12. DatagramPacket dp =newDatagramPacket(buf, buf.length,
  13. InetAddress.getByName("192.168.229.1"),1000);
  14. // 发到哪 InetAddress.getByName("192.168.229.1"),1000别写系统端口

  15. // 3、通过socket服务的send方法将数据包发送出去
  16. ds.send(dp);

  17. // 4、关闭资源
  18. ds.close();
  19. }
  20. }
数据包的方法
 InetAddressgetAddress()
          返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
 byte[]getData()
          返回数据缓冲区。
 intgetLength()
          返回将要发送或接收到的数据的长度。
  1. /*
  2. * 需求:定义一个应用程序,用于接收udp协议传输的数据并处理
  3. *
  4. * 定义udp接收端口
  5. * 思路:
  6. * 1、定义udp的socket服务,通常会监听一个端口。其实就是给这个接收网络应用程序定义一个数字标识,
  7. * 明确哪些数据过来该应用程序可以处理
  8. * 2、定义一个数据包,用于存储接收到的字节数据,可以方便提取数据中的信息
  9. * 3、通过socket的receive方法将接收到的数据存入以定义好的数据包中
  10. * 4、通过数据包中特有功能,将不同的数据取出
  11. * 5、关闭资源
  12. */
  13. publicclassUDPReceive{
  14. publicstaticvoid main(String[] args)throwsException{
  15. // 1、建立udp的socket服务,并指定端点
  16. DatagramSocket ds =newDatagramSocket(1000);

  17. // 2、定义数据包,用于存储数据
  18. byte[] buf =newbyte[1024];
  19. DatagramPacket dp =newDatagramPacket(buf, buf.length);

  20. // 3、通过socket服务的receive方法将接收到的数据存入数据包中
  21. ds.receive(dp);// 阻塞式方法 ,不发送就一直接收

  22. // 4、通过数据包的方法获取其中的数据
  23. // String getHostAddress():返回IP地址字符串文本形式,以这个为主,即以IP地址为主。
  24. String ip = dp.getAddress().getHostAddress();// 获取ip
  25. String data =newString(dp.getData(),0, dp.getLength());// dp.getData()获取数据,不需要获取1024,获取指定长度就行
  26. int port = dp.getPort();// 获取端口号,这里的端口和ip是发送端的,他是随机的,可以在套接字中指定,不指定系统随机分配
  27. System.out.println(ip +"::"+ data +"::"+ port);

  28. // 5、关闭资源
  29. ds.close();
  30. }
  31. }
 

在看一个获取键盘录入的发送端,接收端就不写了,都差不多:
  1. 复制代码
    /*  
     * 发送键盘录入信息  
     */  
    public class UDPSend2 {  
        public static void main(String[] args) throws Exception {  
            DatagramSocket ds = new DatagramSocket();  
            BufferedReader bfr = new BufferedReader(  
                    new InputStreamReader(System.in));  //转换流,转成字节
            String line = null;  
          
           byte[] buf = null;  
            DatagramPacket dp = null;  
            while ((line = bfr.readLine()) != null) {  
                buf = line.getBytes();  
                dp = new DatagramPacket(buf, buf.length,  
                        InetAddress.getByName("192.168.229.1"), 10000);
    //192.168.1.255广播地址,在这个频段里的所有ip都可以接收,聊天室  
                ds.send(dp);  
                  
                if("886".equals(line)){  
                    break;  
                }  
            }  
            ds.close();  
            buf.clone();  
        }  
    }  
    复制代码

     

 

练习:编写一个简单的聊天程序:

分析:

有收数据的部分,有发数据的部分,这两部分需要同时执行,那就需要多线程技术,一个线程控制接收,一个线程控制发。

因为收和发的动作不一致,所以要定义两个run方法,而且这个两个方法要封装到不同的类中。

  1. 复制代码
    public class UDPChatDemo {  
        public static void main(String[] args) throws IOException {  
            DatagramSocket sendSocket = new DatagramSocket();  
            DatagramSocket ReceiveSocket = new DatagramSocket(10002);  
              
            new Thread(new ChatSend(sendSocket)).start();  
            new Thread(new ChatReceive(ReceiveSocket)).start();  
        }  
    }  
    /*  
     * 聊天的发送端  
     */  
    public class ChatSend implements Runnable{  
          
        private DatagramSocket ds;  
          
        public ChatSend(DatagramSocket ds){  
            this.ds = ds;  
        }  
      
        @Override  
        public void run() {  
            BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));  
            byte[] buf = null;  
            String line = null;  
            try {  
                while((line=bfr.readLine()) != null){  
                    buf = line.getBytes();  
                    DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 10002);  
                    ds.send(dp);  
                }  
            } catch (UnknownHostException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }finally{  
                ds.close();  
                try {  
                    bfr.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
          
    }  
    /*  
     * 聊天,接收端  
     */  
    public class ChatReceive implements Runnable{  
          
        private DatagramSocket ds;  
          
        public ChatReceive(DatagramSocket ds){  
            this.ds = ds;  
        }  
      
        @Override  
        public void run() {  
            while(true){  
                byte[] buf = new byte[1024];  
                DatagramPacket dp = new DatagramPacket(buf, buf.length);  
                try {  
                    ds.receive(dp);  
                    String ip = dp.getAddress().getHostAddress();  
                    String data = new String(dp.getData(),0,dp.getLength());  
                    int port = dp.getPort();  
                    System.out.println(ip + "::" + data + "::" + port);  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
      
    }  
    复制代码

     

 
 

第三  TCP传输

TCP传输:

1、流程:

 

  • Socket(客户端)和ServiceSocket服务端()
  • 建立客户端和服务端
  • 建立连接后,通过socket中的IO流进行数据的传输

 

关闭socket

2、方法:

1)创建客户端对象: Socket(String host,int port),指定要接收的IP地址和端口号

2)创建服务端对象:ServerSocket(int port):指定接收的客户端的端口

3)Socket accept():侦听并接受到此套接字的连接,服务器用于接收客户端socket对象的方法

注:服务器没有socket流,也就没有读写操作的流,服务器是通过获取到客户端的socket流然后获取到其中的读写方法,对数据进行操作的,也正是因为这样服务器与客户端的数据操作才不会错乱

4)void shutdownInput():此套接字的输入流至于“流的末尾”

5)void shutdownOutput():禁用此套接字的输出流

6)InputStream getInputStream():返回此套接字的输入流

7)OutputStream getOutputStream():返回套接字的输出流

实例:
 
定义tcp的服务端  
  • 建立服务端的socket服务,ServerSocket,并监听一个端口  
  • 获取连接过来的客服端对象,通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。  
  • 客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。  
  • 关闭服务端(可选)  
  1. 复制代码
    publicclassTCPServerDemo{
    publicstaticvoid main(String[] args)throwsIOException{
    // 建立服务端的socket服务,并监听一个端口
    ServerSocket ss =newServerSocket(10003);
    // 通过accept方法获取连接过来的客户端对象
    Socket socket = ss.accept();
    String ip = socket.getInetAddress().getHostAddress();
    System.out.println(ip +"......connected");
    // 获取客户端发过来的数据,那么要使用客户端对象的读取流来获取数据
    InputStream in = socket.getInputStream();
    byte[] buf =newbyte[1024];
    int len = in.read(buf);
    System.out.println(newString(buf,0, len));
    socket.close();// 关闭客户端
    ss.close();// 关闭服务端,可选的操作
    }
    }
    复制代码

     

 
 
tcp分为客户端和服务端,客服端对象的对象是socket,服务端对应的是serversoceket  
  • 客户端,在建立的时候就可以去连接指定的主机  
  • 因为tcp是面向连接的,所以在建立socket时就需要有服务端存在  
  • 并连接成功,形成通路,才能在该通道上传输数据  
  1. 复制代码
    publicclassTCPClientDemo{
    publicstaticvoid main(String[] args)throwsException{
    //1、创建客户端的socket服务,指定目的主机和端口
    Socket socket =newSocket("192.168.229.1",10003);
    //2、获取socket的输出流,用于发送数据
    OutputStream out = socket.getOutputStream();
    //3、发送数据
    out.write("tcp client send message come on".getBytes());
    socket.close();
    }
    }
    复制代码

     

 
示例二:下面是客户端和服务端互动的例子,建立一个文本转换机制,就是客户端把从键盘录入的数据发送给服务器,服务器将数据转为大写再发给客户端
  1.  
    复制代码
    /*  
     * 需求:建立一个文本转换服务器。  
     * 客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。  
     * 而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。  
     *   
     * 分析:  
     * 客户端  
     * 既然是操作设备上的数据,那就可以使用IO技术,并按照io操作规律来思考  
     * 源:键盘录入  
     * 目的:网络设备,网络输出流  
     * 而且操作的是文本数据,可以用字符流  
     *   
     * 步骤: 
     * 1、建立服务  
     * 2、获取键盘输入  
     * 3、将数据发给客户端  
     * 4、获取服务端返回的数据  
     * 5、结束,关闭资源  
     */  
    class TransClient {  
        public static void main(String[] args) throws UnknownHostException,  
                IOException {  
            Socket s = new Socket(InetAddress.getLocalHost(), 10005);  
            BufferedReader bfrb = new BufferedReader(new InputStreamReader(  
                    System.in));  
      
            // 定义目的,将数据写入socket输出流,发给服务器  
            OutputStream out = s.getOutputStream();  
            OutputStreamWriter ow = new OutputStreamWriter(out);  
            BufferedWriter bfw = new BufferedWriter(ow);  
      
            // 定义读取流  
            InputStream in = s.getInputStream();  
            InputStreamReader is = new InputStreamReader(in);  
            BufferedReader bfr = new BufferedReader(is);  
      
            String line = null;  
            while ((line = bfrb.readLine()) != null) {  
                bfw.write(line);  
                bfw.newLine();  
                bfw.flush();  
      
                // 读取数据  
                String data = bfr.readLine();  
                System.out.println(data);  
            }  
      
            bfrb.close();  
            s.close();  
        }  
    }  
      
    /*  
     * 服务端: 源:socket读取流 目的:socket输出流。  
     */  
    class TransServer {  
        public static void main(String[] args) throws IOException {  
            ServerSocket ss = new ServerSocket(10005);  
            Socket s = ss.accept();  
      
            String ip = s.getInetAddress().getHostAddress();  
            System.out.println(ip + "....connected");  
      
            InputStream in = s.getInputStream();  
            InputStreamReader isr = new InputStreamReader(in);  
            BufferedReader bfr = new BufferedReader(isr);  
      
            // 目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。  
            BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(  
                    s.getOutputStream()));  
              
            String line = null;  
            while((line=bfr.readLine()) != null){  
                bufOut.write(line.toUpperCase());  
                bufOut.newLine();  
                bufOut.flush();  
            }  
            s.close();  
            ss.close();  
        }  
    }  
      
    public class TCPTransText{  
        public static void main(String[] args) {  
            new TransClient();  
            new TransServer();  
        }  
    } 
    复制代码

     

 
示例三:TCP复制文件

1、客户端:

源:硬盘上的文件;目的:网络设备,即网络输出流。若操作的是文本数据,可选字符流,并加入高效缓冲区。若是媒体文件,用字节流。

2、服务端:

源:socket读取流;目的:socket输出流。

3、出现的问题:

现象:

a.文件已经上传成功了,但是没有得到服务端的反馈信息。

b.即使得到反馈信息,但得到的是null,而不是“上传成功”的信息

原因:

a.因为客户端将数据发送完毕后,服务端仍然在等待这读取数据,并没有收到结束标记,就会一直等待读取。

b.上个问题解决后,收到的不是指定信息而是null,是因为服务端写入数据后,也需要刷新,才能将信息反馈给客服端。

解决:

a.方法一:定义结束标记,先将结束标记发送给服务端,让服务端接收到结束标记,然后再发送上传的数据。但是这样定义可能会发生定义的标记和文件中的数据重复而导致提前结束。

   方法二:定义时间戳,由于时间是唯一的,在发送数据前,先获取时间,发送完后在结尾处写上相同的时间戳,在服务端,接收数据前先接收一个时间戳,然后在循环中判断时间戳以结束标记。

  方法三:通过socket方法中的shutdownOutput(),关闭输入流资源,从而结束传输流,以给定结束标记。这里主要用这个方法。

  1. 复制代码
    /*  
     * 客户端  
     */  
    class TextClient {  
        public static void main(String[] args) throws UnknownHostException,  
                IOException {  
            Socket s = new Socket(InetAddress.getLocalHost(), 10007);  
      
            File file = new File("AwtDemo.java");  
      
            BufferedReader bfr = new BufferedReader(new FileReader(file));  
      
            // 将数据写入到socket流中  
            PrintWriter out = new PrintWriter(s.getOutputStream(), true);  
      
            String line = null;  
            while ((line = bfr.readLine()) != null) {  
                out.println(line);  
            }  
            // 关闭客户端的输出流。相当于给流中加入一个结束标记-1.  
            // 结束标记很重要,不然TCP中程序停不下来  
            s.shutdownOutput();  
      
            // 接收服务端发过来的数据  
            BufferedReader bfrs = new BufferedReader(new InputStreamReader(  
                    s.getInputStream()));  
      
            String data = bfrs.readLine();  
            System.out.println(data);  
      
            bfr.close();  
            s.close();  
        }  
    }  
      
    class TextServer {  
        public static void main(String[] args) throws IOException {  
            ServerSocket ss = new ServerSocket(10007);  
            Socket s = ss.accept();// 接收客户端的socket流  
            String ip = s.getInetAddress().getHostAddress();  
            System.out.println(ip + "....connected");  
      
            //建立读取客户端数据的流  
            BufferedReader bfr = new BufferedReader(new InputStreamReader(  
                    s.getInputStream()));  
            //建立文件,关联流  
            PrintWriter out = new PrintWriter(new FileWriter("server.java"),true);  
              
            String line = null;  
            while((line=bfr.readLine()) != null){  
                out.println(line);  
            }  
              
            //建立给客户端回馈机制  
            PrintWriter outToC = new PrintWriter(s.getOutputStream(),true);  
            outToC.println("上传成功");  
              
            out.close();  
            s.close();  
            ss.close();  
        }  
    }  
    复制代码

     


第四  实际应用

一、TCP并发执行请求

一)图片上传:

第一、客户端:

1、创建服务端点

2、读取客户端以后图片数据

3、通过Socket输出流将数据发给服务端

4、读取服务端反馈信息

5、关闭客户端

第二、服务端

对于客户端并发上传图片,服务端如果单纯的使用while(true)循环式有局限性的,当A客户端连接上以后,被服务端获取到,服务端执行具体的流程,这时B客户端连接就只有等待了,因为服务端还未处理完A客户端的请求,还有循环来回执行下须accept方法,所以暂时获取不到B客户端对象,那么为了可让多个客户端同时并发访问服务端,那么服务端最好就是将每个客户端封装到一个单独的线程,这样就可以同时处理多个客户端的请求。如何定义线程呢?只要明确每个客户端要在服务端执行的代码即可,将改代码存入到run方法中。

  1. 复制代码
    /*  
     * 客户端  
     */  
    class PicCilent2 {  
        public static void main(String[] args) throws UnknownHostException,  
                IOException {  
            File file = new File(args[0]);  
            Socket s = new Socket("192.168.229.1", 10010);  
            // 读取文件数据  
            BufferedInputStream bfr = new BufferedInputStream(new FileInputStream(  
                    file));  
            // 将数据写到socket流中,传递给服务端  
            BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());  
      
            byte[] buf = new byte[1024];  
            int len = 0;  
            while ((len = bfr.read(buf)) != -1) {  
                out.write(buf, 0, len);  
            }  
            s.shutdownInput();// 结束标记  
      
            // 接收服务端反馈数据  
            InputStream in = s.getInputStream();  
            byte[] bufin = new byte[1024];  
            int num = in.read(bufin);  
            System.out.println(new String(bufin, 0, num));  
      
            bfr.close();  
            s.close();  
        }  
    }  
      
    /*  
     *   
     * 服务端:  
     */  
    class PicThread implements Runnable {  
      
        private Socket s;  
      
        PicThread(Socket s) {  
            this.s = s;  
        }  
      
        @Override  
        public void run() {  
            int count = 1;  
            String ip = s.getInetAddress().getHostAddress();  
            try {  
                System.out.println(ip + "....connected");  
      
                InputStream in = s.getInputStream();  
      
                File dir = new File("c:\\");  
      
                File file = new File(dir, ip + "(" + (count) + ")" + ".jpg");  
      
                while (file.exists())  
                    file = new File(dir, ip + "(" + (count++) + ")" + ".jpg");  
      
                FileOutputStream fos = new FileOutputStream(file);  
      
                byte[] buf = new byte[1024];  
      
                int len = 0;  
                while ((len = in.read(buf)) != -1) {  
                    fos.write(buf, 0, len);  
                }  
      
                OutputStream out = s.getOutputStream();  
      
                out.write("上传成功".getBytes());  
      
                fos.close();  
      
                s.close();  
            } catch (Exception e) {  
                throw new RuntimeException(ip + "上传失败");  
            }  
        }  
      
    }  
      
    class Picserver2 {  
        public static void main(String[] args) throws IOException {  
            ServerSocket ss = new ServerSocket(10011);  
            while (true) {  
                Socket s = ss.accept();  
      
                new Thread(new PicThread(s)).start();  
            }  
        }  
    }  
    复制代码

     

 
二、其他方式访问服务器:

1、浏览器

在浏览器地址栏输入你的IP和你的服务器的端口号,这就可以成功通过浏览器访问自己的服务器了。

2、telnet

telnet是windows提供的远程登录工具,可以连接服务器的任意一台主机,并在通过dos命令行配置服务器 访问方式:IP 端口号--> 192.168.229.1 端口号

2、 客户端:浏览器。
 服务端:Tomcat服务器。

启动tomcat服务器,自己写点数据用于服务器返回给客户端的数据,这里是html文件,自己写一个简单的html文件放在tomcat的webapps目录下就可以

3、客户端:自定义。(图形界面)
 服务端:Tomcat服务器。


第五  原理

最常见的客户端:
浏览器 :IE。
最常见的服务端:
服务器:Tomcat。
 
原理:
自定义服务端, 使用已有的客户端IE,了解一下客户端给服务端发了什么请求?
  1. publicclassMyTomcat{

  2. /**
  3. * @param args
  4. * @throws IOException
  5. */
  6. publicstaticvoid main(String[] args)throwsIOException{

  7. ServerSocket ss =newServerSocket(9090);

  8. Socket s = ss.accept();
  9. System.out.println(s.getInetAddress().getHostAddress()+".....connected");

  10. InputStream in = s.getInputStream();

  11. byte[] buf =newbyte[1024];

  12. int len = in.read(buf);
  13. String text =newString(buf,0,len);
  14. System.out.println(text);


  15. //给客户端一个反馈信息。
  16. PrintWriter out =newPrintWriter(s.getOutputStream(),true);

  17. out.println("<font color='red' size='7'>欢迎光临</font>");

  18. s.close();
  19. ss.close();
  20. }

  21. }
发送的请求是( 输出的text ):
GET / HTTP/1.1  请求行  请求方式  /myweb/1.html  请求的资源路径   http协议版本。
请求消息头 . 属性名:属性值
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, 
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept: */*     
Accept-Language: zh-cn,zu;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
Host: 192.168.1.100:9090
//Host: www.huyouni.com:9090
Connection: Keep-Alive
//空行
//请求体。
 
知道了发送了什么,那么就可以模拟一个浏览器
  1. publicclassMyBrowser{

  2. /**
  3. * @param args
  4. * @throws IOException
  5. * @throws UnknownHostException
  6. */
  7. publicstaticvoid main(String[] args)throwsUnknownHostException,IOException{

  8. Socket s =newSocket("192.168.1.100",8080);

  9. //模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
  10. PrintWriter out =newPrintWriter(s.getOutputStream(),true);
  11. out.println("GET /myweb/1.html HTTP/1.1");
  12. out.println("Accept: */*");
  13. out.println("Host: 192.168.1.100:8080");
  14. out.println("Connection: close");
  15. out.println();
  16. out.println();


  17. InputStream in = s.getInputStream();

  18. byte[] buf =newbyte[1024];
  19. int len = in.read(buf);

  20. String str =newString(buf,0,len);
  21. System.out.println(str);

  22. s.close();

  23. //http://192.168.1.100:8080/myweb/1.html
  24. }

  25. }
//服务端发回应答消息。
HTTP/1.1 200 OK   //应答行,http的协议版本   应答状态码   应答状态描述信息
 
应答消息属性信息。 属性名:属性值
Server: Apache-Coyote/1.1
ETag: W/"199-1323480176984"
Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
Content-Type: text/html
Content-Length: 199
Date: Fri, 11 May 2012 07:51:39 GMT
Connection: close
//空行
//应答体。
<html>
<head>
<title>这是我的网页</title>
</head>
 
<body>
 
<h1>欢迎光临</h1>
 
<font size='5' color="red">这是一个tomcat服务器中的资源。是一个html网页。</font>
</body>
 
 
</html>
 
可是浏览器并没有显示应答消息属性信息这些内容,因为浏览器有自己的解析引擎,Java封装了一个类URL可以解析引擎
  1. publicclassURLDemo{

  2. /**
  3. * @param args
  4. * @throws IOException
  5. */
  6. publicstaticvoid main(String[] args)throwsIOException{

  7. String str_url ="http://192.168.1.100:8080/myweb/1.html";

  8. URL url =new URL(str_url);

  9. // System.out.println("getProtocol:"+url.getProtocol());
  10. // System.out.println("getHost:"+url.getHost());
  11. // System.out.println("getPort:"+url.getPort());
  12. // System.out.println("getFile:"+url.getFile());
  13. // System.out.println("getPath:"+url.getPath());
  14. // System.out.println("getQuery:"+url.getQuery());
  15. //这一部简化了下面的俩步
  16. // InputStream in = url.openStream();

  17. //获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
  18. URLConnection conn = url.openConnection();

  19. // String value = conn.getHeaderField("Content-Type");
  20. // System.out.println(value);

  21. // System.out.println(conn);
  22. //sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html

  23. InputStream in = conn.getInputStream();

  24. byte[] buf =newbyte[1024];
  25. int len = in.read(buf);

  26. String text =newString(buf,0,len);

  27. System.out.println(text);

  28. in.close();
  29. }

  30. }
 
网络结构,
  • C/S  client/server
特点:
该结构的软件,客户端和服务端都需要编写。
可发成本较高,维护较为麻烦。
 
好处:
客户端在本地可以分担一部分运算。
 
  • B/S  browser/server
特点:
该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。 
开发成本相对低,维护更为简单。
缺点:所有运算都要在服务端完成。
 
 
 
 
 
 
 

小知识点

1、InetSocketAddress对象(IP+端口)

2、ServerSocket对象中的构造函数:

ServerSocket(int port,int backlog),其中的backlog表示队列的最大长度,即最多连入客户端的个数,即最大连接数。

3、在进行浏览器输入网址访问一台主机所做的操作:

如http://192.168.229.1:8080/myweb/demo.html,一般直接输入主机名:http://baidu.com等,那么如何通过主机名获取IP地址,从而连接到这台主机的呢?这就需要将主机名翻译成IP地址,即域名解析:DNS(存的是主机名和IP相对应的键值对)

在进行访问的时候,会现在本地的hosts文件(C:\WINDOWS\system32\drivers\etc\hosts)中找对应的映射,若有,则直接返回请求,若无,则到公网的映射列表即DNS中找对应的映射,找到后,将主机名对应的IP地址返回给本机,本机通过这个IP地址找到对应的服务器。

域名解析示意图:

host应用:

1、可屏蔽一些恶意网址,即将对应的映射关系写入hosts中,将IP地址改为本机的回环地址,那么会直接找到hosts,就不会将请求发送出去了。

2、不让软件更新,可以越过一些收费软件的限制。

3、把经常上的网站写入文件中,提高访问速率。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值