JAVA网络编程

【网络模型】

OSI          应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TCP/IP       --------应用层--------、传输层、网际层、----主机至网络层--    

【网络通讯要素】

IP地址

端口号

传输协议

【网络分层】


1.物理层

主要定义物理设备标准,如网线的接口类型,光纤的接口类型、各种传输介质的
传输速率等。它的主要作是传输比特流(就是由1、0转化为电流强弱来进行传输
到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特


2.数据链路层


主要从物理层接收的数据进行MAC(网卡的地址)的封装与解封装。常把这一层的数据叫做
帧。在这一层工作的设备是交换机,数据通过交换机来传输。

3.网络层

主要将从下层接收到的数据进行IP地址(例如:192.168.0.1)的封装与解封装。在这一层的
工作设备是路由器,常把这一层叫做数据包。

4.传输层

定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低
,可靠性强用于传输可靠性要求高,数据量大的数据),UDP(用户数据包协议,与TCP特性恰恰相反
,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要
是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。

5.会话层

通过传输层(端口号:传输端口与接收端口)建立数据传输的同路。主要在你的系统之间发起会话或者接收
会话请求(设备之间需要互相认识可以是IP也可以是MAC或者主机名)


6.表示层

主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能识别的东西转成人可以识别的
的东西如:图片、声音)

7.应用层


主要是一些终端应用,比如说FTP(各种文件下载)、WEB(IE浏览),QQ之类的。(可以理解为我们再电脑屏幕上可以看到的东西,就是终端应用)


【网络通讯要素】

1.IP地址:InetAddress

网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1主机名:localhost

IP地址
由四段数字,每段数字一个字节组成,范围是(0~255)。

因为由四段数字组成的排列组合是有限的,当年国际标准化组织通过子网掩码将把IP地址分成了A类B类C类,每一类都有自己的用途,我们一般用的是C类地址段,而全球的计算机又那么多,所以就不可能每台计算机
分配一个IP,这个时候就形成了很多局域网,通过一个代理服务器分配一个公共的IP地址。

现在地址不够了,就推出了IPV4版本,后面又有IPV6版本,这些版本融入了字母


端口号

用于标识进程的逻辑地址,不同进程的标识
有效端口:0-65335,其中0-1027系统使用或保留端口,我们尽量不要使用。

传输协议

通讯的规则
常见协议:UDP、TCP


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

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

【InetAddress】
因为IP地址相对来说内容比较复杂,而且它又有自己的主机名相对应,
所以IP地址在JAVA中也被封装成了对象InetAddress。

//获取本地主机IP地址对象
InetAddress ip=InetAddress.getLocalHost();
//获取其他主机的IP地址对象,可以通过主机名和IP获取
ip=InetAddress.getByName("192.160.1.102");
//ip=InetAddress.getByName("主机名");

System.out.println(ip.getHostAddress());//获取主机地址

System.out.println(ip.getHostName());//获取主机名

【域名解析】

我们在去访问一台主机的时候,比如说通过浏览器访问新浪网页,我们需要去访问它的主机(10.1.1.1),
那么按道理我们应该在浏览器里面输入它的IP地址来进行访问,凡是访问其他主机走的必须是IP,但是由于
互联网上面的主机非常多,主机也非常多,我们不可能记住所有的IP。所以国际组织就想到了一个方法,我们给
主机起名字,记名字就好办多了,如:http://www.sina.com.cn(www是主机名,sina代表域名,com代表商业化组织,以营利为主,org是营利的),这样的域名。
但是当我们在浏览器里面输入这个一串之后,并不是直接访问新浪的主机,在互联网上有很多台公共的服务器,他们里边就存放着主机和IP的对应关系,
输入网址后访问的就是这台主机,这台主机的名字就叫做(DNS),然后通过DNS找到和主机名对应IP供我们访问。

那我们上网为什么都没有去访问过DNS,也没有指定过DNS呢?
这是因为宽带运营商已经为我们指定了。

本地解析:

我们可以在自己本机配置域名解析,在C:\Windows\System32\drivers\etc\hosts这个文件中配置
其实域名解析一开始并不是直接访问互联网,而是先走的本机解析,本地解析不了才走互联网。


【Socket】
就是为网络服务提供的一种机制。
通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Soket间通过IO传输

可以理解为对讲机,可以发送也可以接收

【UDP传输】
DatagramSocket与DatagramPacket(数据包)
建立发送端,接收端。
建立数据包
调用Socket的发送接收方法
关闭Socket。
发送与接收端是两个独立的运行程序

【发送】

public class UDPSendDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        System.out.println("发送端启动......");
        /*
         * 创建UDP传输的发送端。
         * 思路:
         * 1,建立udp的socket服务。
         * 2,将要发送的数据封装到数据包中。 
         * 3,通过udp的socket服务将数据包发送出去。
         * 4,关闭socket服务。
         */
        //1,udpsocket服务。使用DatagramSocket对象。
        DatagramSocket ds = new DatagramSocket(8888);
        
        //2,将要发送的数据封装到数据包中。
        String str = "udp传输演示:哥们来了!";
            //使用DatagramPacket将数据封装到的该对象包中。
        byte[] buf = str.getBytes();
        
        DatagramPacket dp = 
                new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
        
        
        //3,通过udp的socket服务将数据包发送出去。使用send方法。
        ds.send(dp);
        
        //4,关闭资源。
        ds.close();
        
        
    }

}


改成在控制台输入


public class UDPSendDemo2 {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        System.out.println("发送端启动......");
        /*
         * 创建UDP传输的发送端。
         * 思路:
         * 1,建立udp的socket服务。
         * 2,将要发送的数据封装到数据包中。 
         * 3,通过udp的socket服务将数据包发送出去。
         * 4,关闭socket服务。
         */
        //1,udpsocket服务。使用DatagramSocket对象。
        DatagramSocket ds = new DatagramSocket(8888);
        
        
//        String str = "udp传输演示:哥们来了!";
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        
        while((line=bufr.readLine())!=null){
            
            
            byte[] buf = line.getBytes();
            DatagramPacket dp = 
                    new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
            ds.send(dp);
            
            if("886".equals(line))
                break;
        }
        
        //4,关闭资源。
        ds.close();
        
        
    }

}

【接收】

public class UDPReceDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        System.out.println("接收端启动......");
        /*
         * 建立UDP接收端的思路。
         * 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
         * 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
         * 3,使用socket服务的receive方法将接收的数据存储到数据包中。
         * 4,通过数据包的方法解析数据包中的数据。
         * 5,关闭资源 
         */
        
        //1,建立udp socket服务。
        DatagramSocket ds = new DatagramSocket(10000);
        
        
        //2,创建数据包。
        byte[] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf,buf.length);
        
        //3,使用接收方法将数据存储到数据包中。
        ds.receive(dp);//阻塞式的。
        
        //4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
        String ip = dp.getAddress().getHostAddress();
        int port = dp.getPort();
        String text = new String(dp.getData(),0,dp.getLength());
        
        System.out.println(ip+":"+port+":"+text);
        
        //5,关闭资源。
        ds.close();
        
        
    }
    

}
改成不关闭


public class UDPReceDemo2 {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        System.out.println("接收端启动......");
        /*
         * 建立UDP接收端的思路。
         * 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
         * 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
         * 3,使用socket服务的receive方法将接收的数据存储到数据包中。
         * 4,通过数据包的方法解析数据包中的数据。
         * 5,关闭资源 
         */
        
        //1,建立udp socket服务。
        DatagramSocket ds = new DatagramSocket(10000);
        
        while(true){
        
        //2,创建数据包。
        byte[] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf,buf.length);
        
        //3,使用接收方法将数据存储到数据包中。
        ds.receive(dp);//阻塞式的。
        
        //4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
        String ip = dp.getAddress().getHostAddress();
        int port = dp.getPort();
        String text = new String(dp.getData(),0,dp.getLength());
        
        System.out.println(ip+":"+port+":"+text);
        
        
        }
        //5,关闭资源。
//        ds.close();
        
        
    }
    

}


【聊天室】
发送线程任务:


public class Send implements Runnable {

    private DatagramSocket ds;
    
    public Send(DatagramSocket ds){
        this.ds = ds;
    }
    
    @Override
    public void run() {
        
        try {
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            
            while((line=bufr.readLine())!=null){
                
                
                byte[] buf = line.getBytes();
                //DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10001);
                //在我们的IP地址段,我们如果走的是c类地址的话,如:192.168.1.100  子网掩码是255.255.255.0
                    //那么192.168.1都是网络位,100是IP地址位(1~254),255是广播地址位。
                DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10001);
                ds.send(dp);
                
                if("886".equals(line))
                    break;
            }
            
            ds.close();
        } catch (Exception e) {
        }
    }

}

接收线程任务:

public class Rece implements Runnable {

    private DatagramSocket ds;

    public Rece(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            while (true) {

                // 2,创建数据包。
                byte[] buf = new byte[1024];
                DatagramPacket dp = new DatagramPacket(buf, buf.length);

                // 3,使用接收方法将数据存储到数据包中。
                ds.receive(dp);// 阻塞式的。

                // 4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
                String ip = dp.getAddress().getHostAddress();
                int port = dp.getPort();
                String text = new String(dp.getData(), 0, dp.getLength());
                
                System.out.println(ip + "::" + text);
                if(text.equals("886")){
                    System.out.println(ip+"....退出聊天室");
                }

            }
        } catch (Exception e) {

        }

    }

}


测试:

public class ChatDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        
        DatagramSocket send = new DatagramSocket();
        
        DatagramSocket rece = new DatagramSocket(10001);
        new Thread(new Send(send)).start();
        new Thread(new Rece(rece)).start();
        
    }

}


【TCP连接】

客户端:

public class ClientDemo {

    /**
     * @param args
     * @throws IOException 
     * @throws UnknownHostException 
     */
    public static void main(String[] args) throws UnknownHostException, IOException {
        //客户端发数据到服务端
        /*
         * Tcp传输,客户端建立的过程。
         * 1,创建tcp客户端socket服务。使用的是Socket对象。
         *         建议该对象一创建就明确目的地。要连接的主机。 
         * 2,如果连接建立成功,说明数据传输通道已建立。
         *         该通道就是socket流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。
         *         想要输入或者输出流对象,可以找Socket来获取。 
         *         可以通过getOutputStream(),和getInputStream()来获取两个字节流。
         * 3,使用输出流,将数据写出。 
         * 4,关闭资源。 
         */
        
        
        //创建客户端socket服务。
        Socket socket = new Socket("192.168.1.100",10002);
        
        //获取socket流中的输出流。 
        OutputStream out = socket.getOutputStream();
        
        
        //使用输出流将指定的数据写出去。
        out.write("tcp演示:哥们又来了!".getBytes());
        
        //关闭资源。
        socket.close();
        
        
        
        
        
        
    }

}


服务端:


public class ServerDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
//        服务端接收客户端发送过来的数据,并打印在控制台上。 
        /*
         * 建立tcp服务端的思路:
         * 1,创建服务端socket服务。通过ServerSocket对象。
         * 2,服务端必须对外提供一个端口,否则客户端无法连接。
         * 3,获取连接过来的客户端对象。
         * 4,通过客户端对象获取socket流读取客户端发来的数据 
         *         并打印在控制台上。
         * 5,关闭资源。关客户端,关服务端。 
         */
        
        //1创建服务端对象。
        ServerSocket ss = new ServerSocket(10002);
        
        //2,获取连接过来的客户端对象。
        Socket s = ss.accept();//阻塞式.
        
        String ip = s.getInetAddress().getHostAddress();
        
        //3,通过socket对象获取输入流,要读取客户端发来的数据
        InputStream in = s.getInputStream();
        
        byte[] buf = new byte[1024];
        
        int len = in.read(buf);
        String text = new String(buf,0,len);
        System.out.println(ip+":"+text);
        
        
        
        
        
                
        s.close();
        ss.close();
        
    }

}

客户端和服务端交互:


public class ClientDemo2 {

    /**
     * @param args
     * @throws IOException 
     * @throws UnknownHostException 
     */
    public static void main(String[] args) throws UnknownHostException, IOException {
        //客户端发数据到服务端
        /*
         * Tcp传输,客户端建立的过程。
         * 1,创建tcp客户端socket服务。使用的是Socket对象。
         *         建议该对象一创建就明确目的地。要连接的主机。 
         * 2,如果连接建立成功,说明数据传输通道已建立。
         *         该通道就是socket流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。
         *         想要输入或者输出流对象,可以找Socket来获取。 
         *         可以通过getOutputStream(),和getInputStream()来获取两个字节流。
         * 3,使用输出流,将数据写出。 
         * 4,关闭资源。 
         */
        
        
        
        Socket socket = new Socket("192.168.1.100",10002);
        
        
        OutputStream out = socket.getOutputStream();    
        
        
        out.write("tcp演示:哥们又来了!".getBytes());
        
        
        
        //读取服务端返回的数据,使用socket读取流。 
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[1024];
        
        int len = in.read(buf);
        
        String  text = new String(buf,0,len);
        
        System.out.println(text);
        
        
        
        //关闭资源。
        socket.close();
        
        
        
        
        
        
    }

}


public class ServerDemo2 {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
//        服务端接收客户端发送过来的数据,并打印在控制台上。 
        /*
         * 建立tcp服务端的思路:
         * 1,创建服务端socket服务。通过ServerSocket对象。
         * 2,服务端必须对外提供一个端口,否则客户端无法连接。
         * 3,获取连接过来的客户端对象。
         * 4,通过客户端对象获取socket流读取客户端发来的数据 
         *         并打印在控制台上。
         * 5,关闭资源。关客户端,关服务端。 
         */
        
        //1创建服务端对象。
        ServerSocket ss = new ServerSocket(10002);
        
        //2,获取连接过来的客户端对象。
        Socket s = ss.accept();
        
        String ip = s.getInetAddress().getHostAddress();
        
        //3,通过socket对象获取输入流,要读取客户端发来的数据
        InputStream in = s.getInputStream();
        
        byte[] buf = new byte[1024];
        
        int len = in.read(buf);
        String text = new String(buf,0,len);
        System.out.println(ip+":"+text);
        
        
        
        //使用客户端socket对象的输出流给客户端返回数据
        OutputStream out = s.getOutputStream();
        out.write("收到".getBytes());
        
        s.close();
        ss.close();
        
    }

}

【常见客户端和服务端】

最常见的客户端
IE
最常见的服务端
Tomcat  

能将服务器里面所对外提供的资源放在它的目录下,它可以将这些资源读取并且发给客户端

服务端的开发就是基于Tomcat处理请求以及应答,而要实现处理请求以及应答,就必须要符合

Tomcat的规则来编写代码,照着它的接口做就能实现处理请求以及应答,它对外提供的接口就是interface Servlet

为了了解其原理:
1.
定义服务端,
使用已有的客户端IE,了解一下客户端给服务端发了什么请求?
public class MyTomcat {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        ServerSocket ss = new ServerSocket(9090);
        
        Socket s = ss.accept();
        System.out.println(s.getInetAddress().getHostAddress()+".....connected");
        
        InputStream in = s.getInputStream();
        
        byte[] buf = new byte[1024];
        
        int len = in.read(buf);
        String text = new String(buf,0,len);
        System.out.println(text);
        
        
        //给客户端一个反馈信息。
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);
        
        out.println("<font color='red' size='7'>欢迎光临</font>");
        
        s.close();
        ss.close();
    }

}

发送的请求是


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  连接是否保存
//空行
//请求体。

【http】

超文本传输协议。(它里面涉及的语言是html,为什么我们要用这种协议呢?其实是我们想要在外网进行超文本语言的数据传输)

这个是应用层给我们提供的一种通讯协议,它定义了一种web端,web浏览器和服务端之间的一种通讯规则


为什么要有这个协议呢?

因为web端,web浏览器要想和服务端进行通讯,那么浏览器和服务端就必须遵循相同的规则,才可以。

其实浏览器本身就内置了http的解析程序。称之为解析引擎。

我们用的UDP和TCP并没有直接去操作协议,我们都是用的封装这些协议的对象,这些都是底层做的,不是我们做的。

像这种协议有很多比如说FTP,操作文件的,用于文件上传下载。

所以当我们在浏览器里面输入网址的时候,浏览器都是按http协议的方式封装好然后再发送到服务器的。

比如:http\\:www.sina.com.cn/index.html

www.sina.com,会通过域名解析器得到IP地址,index.html请求的资源路径。


然后就封装成:

GET /index.html HTTP/1.1  请求行  请求方式  /index.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: www.sina.com.cn
Connection: Keep-Alive
//空行
//请求体。


就发送到服务端了,服务端拿到这个数据之后,就进行解析,然后根据发送过来的这些数据做相应的处理。


所以我们的软件向Tomcat请求的时候也需要像浏览器一样封装这些请求头


public class MyBrowser {

    /**
     * @param args
     * @throws IOException 
     * @throws UnknownHostException 
     */
    public static void main(String[] args) throws UnknownHostException, IOException {

        Socket s = new Socket("192.168.1.100",8080);
        
        //模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);
        out.println("GET /myweb/1.html HTTP/1.1");
        out.println("Accept: */*");
        out.println("Host: 192.168.1.100:8080");
        out.println("Connection: close");
        out.println();
        out.println();
        
        
        InputStream in = s.getInputStream();
        
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        
        String str =new String(buf,0,len);
        System.out.println(str);
        
        s.close();
        
        //http://192.168.1.100:8080/myweb/1.html
    }

}


//服务端发回应答消息。
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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值