17:网络编程

第一  概述

一、概述:

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. DatagramSocket ds =newDatagramSocket(8888);
  9. // 2、确定数据,并封装成数据包DatagramPacket(byte[] buf, int length, InetAddress,address, int port)
  10. byte[] buf ="udp send message come on".getBytes();// 数据 ,转成字节数组
  11. DatagramPacket dp =newDatagramPacket(buf, buf.length,
  12. InetAddress.getByName("192.168.229.1"),1000);
  13. // 发到哪 InetAddress.getByName("192.168.229.1"),1000别写系统端口
  14. // 3、通过socket服务的send方法将数据包发送出去
  15. ds.send(dp);
  16. // 4、关闭资源
  17. ds.close();
  18. }
  19. }

数据包的方法

InetAddress

getAddress()          返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。

byte[]

getData()          返回数据缓冲区。

int

getLength()          返回将要发送或接收到的数据的长度。

/*  
 * 需求:定义一个应用程序,用于接收udp协议传输的数据并处理  
 *   
 * 定义udp接收端口  
 * 思路:  
 * 1、定义udp的socket服务,通常会监听一个端口。其实就是给这个接收网络应用程序定义一个数字标识,  
 *    明确哪些数据过来该应用程序可以处理  
 * 2、定义一个数据包,用于存储接收到的字节数据,可以方便提取数据中的信息  
 * 3、通过socket的receive方法将接收到的数据存入以定义好的数据包中  
 * 4、通过数据包中特有功能,将不同的数据取出  
 * 5、关闭资源  
 */
publicclassUDPReceive{
publicstaticvoid main(String[] args)throwsException{
// 1、建立udp的socket服务,并指定端点
DatagramSocket ds =newDatagramSocket(1000);

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

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

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

// 5、关闭资源
		ds.close();
}
}

在看一个获取键盘录入的发送端,接收端就不写了,都差不多:

/*  
 * 发送键盘录入信息  
 */  
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方法,而且这个两个方法要封装到不同的类中。

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方法。没有连接就会等,所以这个方法阻塞式的。  
  • 客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。  
  • 关闭服务端(可选)  
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时就需要有服务端存在  
  • 并连接成功,形成通路,才能在该通道上传输数据  
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();
}
}

示例二:下面是客户端和服务端互动的例子,建立一个文本转换机制,就是客户端把从键盘录入的数据发送给服务器,服务器将数据转为大写再发给客户端

/*  
 * 需求:建立一个文本转换服务器。  
 * 客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。  
 * 而且客户度可以不断的进行文本转换。当客户端输入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(),关闭输入流资源,从而结束传输流,以给定结束标记。这里主要用这个方法。

/*  
 * 客户端  
 */  
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方法中。

/*  
 * 客户端  
 */  
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 条评论
登录 后参与评论

相关文章

来自专栏别先生

基于jsp+servlet图书管理系统之后台用户信息插入操作

前奏:   刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长...

3766
来自专栏Java Web

Java I/O不迷茫,一文为你导航!

学习过计算机相关课程的童鞋应该都知道,I/O 即输入Input/ 输出Output的缩写,最容易让人联想到的就是屏幕这样的输出设备以及键盘鼠标这一类的输入设备,...

1182
来自专栏Android 研究

OKHttp源码解析(四)--中阶之拦截器及调用链

那我们书接上文。上篇文章已经说明了OKHttp有两种调用方式,一种是阻塞的同步请求,一种是异步的非阻塞的请求。但是无论同步还是异步都会调用下RealCall的 ...

2464
来自专栏Golang语言社区

理解Go语言Web编程(下)

ListenAndServe函数 前面所有示例程序中,都在main函数中调用了ListenAndServe函数。下面对此函数所做的工作进行分析。该函数的实现为:...

7146
来自专栏PHP在线

PHP 面试知识梳理

算法与数据结构 BTree和B+tree BTree B树是为了磁盘或者其他存储设备而设计的一种多叉平衡查找树,相对于二叉树,B树的每个内节点有多个分支,即多叉...

4796
来自专栏JackieZheng

探秘Tomcat——从一个简陋的Web服务器开始

前言:   无论是之前所在实习单位小到一个三五个人做的项目,还是如今一个在做的百人以上的产品,一直都能看到tomcat的身影。工作中经常遇到的操作就是启动和关闭...

2087
来自专栏流柯技术学院

loadrunner之java user脚本开发

* LoadRunner Java script. (Build: _build_number_)

1634
来自专栏编程思想之路

WiFiAp探究实录--功能实现与源码分析

Android虐我千百遍,我待Android如初恋。 ——————编辑于2017-08-02——————— wifi热点说的是wifiAp相...

1.6K9
来自专栏有趣的django

Django rest framework源码分析(2)----权限

添加权限 (1)API/utils文件夹下新建premission.py文件,代码如下: message是当没有权限时,提示的信息 # utils/permi...

40610
来自专栏菩提树下的杨过

ZooKeeper 笔记(5) ACL(Access Control List)访问控制列表

zk做为分布式架构中的重要中间件,通常会在上面以节点的方式存储一些关键信息,默认情况下,所有应用都可以读写任何节点,在复杂的应用中,这不太安全,ZK通过ACL机...

8076

扫码关注云+社区

领取腾讯云代金券