Java 网络编程

网络编程

网络模型
 OSI参考模型
  //应用层 表示层 会话层 传输层 网络层 数据链路层 物理层
 TCP/IP参考模型
  //应用层 传输层 网际层 网络接口层
网络通讯要素
 IP地址
  //网络中设备的标识 本地回环地址 127.0.0.1 主机名 localhost
 端口号
  //标识进程的逻辑地址 有效端口 0~65535 其中0~1024系统使用或保留端口
 传输协议
  //通讯的规则 TCP UDP
UDP
 将数据及源和目的 封装成数据包中 不需要建立连接
 每个数据包的大小限制在64K内
 因无连接 是不可靠协议
 不需要建立连接 速度快
TCP
 建立连接 形成传输数据的通道
 在连接中进行大数据量传输
 通过三次握手完成连接 是可靠协议
 必须建立连接 效率会稍低

InetAddress //IP地址
 getLocalHost //获取本地地址IP对象
 getHostAddress //IP地址字符串
 getHostName //IP主机名

public class IPDemo {

    public static void main(String[] args) throws UnknownHostException {

        //获取本地主机ip地址对象。 
        InetAddress ip = InetAddress.getLocalHost();
        
        //获取其他主机的ip地址对象。
        ip = InetAddress.getByName("192.168.1.110");//InetAddress.getByName("my_think");
        
        System.out.println(ip.getHostAddress());
        System.out.println(ip.getHostName());
    }

}

Socket  

  Socket就是为网络服务提供的一种机制  

  通信的两端都有Socket  

  网络通信其实就是Socket间的通信  

  数据在两个Socket间通过IO传输

UDP传输  

  DatagramSocket与DatagramPacket  

  建立发送端 接收端  建立数据包  调用Socket的发送接收方法  

  关闭Socket  

  发送端与接收端是两个独立的运行程序

public class UDPSendDemo {

    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 UDPReceDemo {

    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 UDPSendDemo2 {

    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 UDPReceDemo2 {

    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 ChatDemo {

    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();
        
    }

}
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.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) {

        }

    }

}

TCP传输
   Socket和ServerSocket
   建立客户端和服务器端
   建立连接后 通过Socket中的IO流进行数据传输

public class ServerDemo {

    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 ClientDemo {

    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 ServerDemo2 {

    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();
        
    }

}
public class ClientDemo2 {

    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();
        
    }

}

两个练习Demo
1 将客户端发送的小写字母转换为大写字母 输入over结束
2 上传文本到服务端

TCP上传图片 多线程

public class UploadPicServer {

    public static void main(String[] args) throws IOException {
            
        //创建tcp的socket服务端。
        ServerSocket ss = new ServerSocket(10006);
        
        while(true){
            Socket s = ss.accept();            
            
            new Thread(new UploadTask(s)).start();        
            
        }
        //获取客户端。
        
        
//        ss.close();
        
        
    }

}
public class UploadTask implements Runnable {

    private static final int SIZE = 1024*1024*2;
    private Socket s;

    public  UploadTask(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {

        int count = 0;
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip + ".....connected");
        
        try{

        // 读取客户端发来的数据。
        InputStream in = s.getInputStream();

        // 将读取到数据存储到一个文件中。
        File dir = new File("c:\\pic");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir, ip + ".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);
            
            if(file.length()>SIZE){
                System.out.println(ip+"文件体积过大");
                
                fos.close();
                s.close();
                
                
                System.out.println(ip+"...."+file.delete());
                
                return ;
            }
        }

        // 获取socket输出流,将上传成功字样发给客户端。
        OutputStream out = s.getOutputStream();
        out.write("上传成功".getBytes());

        fos.close();
        s.close();
        }catch(IOException e){
            
        }

    }

}
public class UploadPicClient {

    public static void main(String[] args) throws UnknownHostException, IOException {

        
        //1,创建客户端socket。
        Socket s = new Socket("192.168.1.100",10006);
        
        //2,读取客户端要上传的图片文件。
        FileInputStream fis = new FileInputStream("c:\\0.bmp");
        
        //3,获取socket输出流,将读到图片数据发送给服务端。
        OutputStream out = s.getOutputStream();
        
        byte[] buf = new byte[1024];
        
        int len = 0;
        
        while((len=fis.read(buf))!=-1){
            out.write(buf,0,len);
        }
        
        //告诉服务端说:这边的数据发送完毕。让服务端停止读取。
        s.shutdownOutput();
        
        
        //读取服务端发回的内容。         
        InputStream in  = s.getInputStream();
        byte[] bufIn = new byte[1024];
        
        int lenIn = in.read(buf);
        String text = new String(buf,0,lenIn);
        System.out.println(text);
        
        fis.close();
        s.close();    
        
    }

}

客户端服务端模型 最常见的客户端:  浏览器 :IE。 最常见的服务端:  服务器:Tomcat。

为了了解其原理:

自定义服务端, 使用已有的客户端IE,了解一下客户端给服务端发了什么请求?

发送的请求是:

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/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>

Demo

public class MyTomcat {

    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();
    }

}
public class MyBrowser {

    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
    }

}
public class URLDemo {

    public static void main(String[] args) throws IOException {

        String str_url = "http://192.168.1.100:8080/myweb/1.html";
        
        URL url = new URL(str_url);
        
//        System.out.println("getProtocol:"+url.getProtocol());
//        System.out.println("getHost:"+url.getHost());
//        System.out.println("getPort:"+url.getPort());
//        System.out.println("getFile:"+url.getFile());
//        System.out.println("getPath:"+url.getPath());
//        System.out.println("getQuery:"+url.getQuery());
        
//        InputStream in = url.openStream();
        
        //获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
        URLConnection conn = url.openConnection();
        
//        String value = conn.getHeaderField("Content-Type");
//        System.out.println(value);
        
//        System.out.println(conn);
        //sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html
        
        InputStream in = conn.getInputStream();
        
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        
        String text = new String(buf,0,len);
        
        System.out.println(text);
        
        in.close();

    }

}

网络结构

1,C/S  client/server    

  特点:   该结构的软件,客户端和服务端都需要编写。   可发成本较高,维护较为麻烦。     好处:   客户端在本地可以分担一部分运算。

2,B/S  browser/server  

  特点:   该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。   开发成本相对低,维护更为简单。  缺点:所有运算都要在服务端完成。

一个简单浏览器的实现

public class MyBrowseGUI extends javax.swing.JFrame {
    private JTextField url_text;
    private JButton goto_but;
    private JScrollPane jScrollPane1;
    private JTextArea page_content;

    /**
    * Auto-generated main method to display this JFrame
    */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MyBrowseGUI inst = new MyBrowseGUI();
                inst.setLocationRelativeTo(null);
                inst.setVisible(true);
            }
        });
    }
    
    public MyBrowseGUI() {
        super();
        initGUI();
    }
    
    private void initGUI() {
        try {
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            getContentPane().setLayout(null);
            {
                url_text = new JTextField();
                getContentPane().add(url_text);
                url_text.setBounds(12, 36, 531, 44);
                url_text.addKeyListener(new KeyAdapter() {
                    public void keyPressed(KeyEvent evt) {
                        url_textKeyPressed(evt);
                    }
                });
            }
            {
                goto_but = new JButton();
                getContentPane().add(goto_but);
                goto_but.setText("\u8f6c \u5230");
                goto_but.setBounds(555, 36, 134, 44);
                goto_but.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {
                        goto_butActionPerformed(evt);
                    }
                });
            }
            {
                jScrollPane1 = new JScrollPane();
                getContentPane().add(jScrollPane1);
                jScrollPane1.setBounds(12, 92, 676, 414);
                {
                    page_content = new JTextArea();
                    jScrollPane1.setViewportView(page_content);
                }
            }
            pack();
            this.setSize(708, 545);
        } catch (Exception e) {
            //add your error handling code here
            e.printStackTrace();
        }
    }
    
    private void goto_butActionPerformed(ActionEvent evt) {
        showPage();
    }
    
    private void url_textKeyPressed(KeyEvent evt) {
        if(evt.getKeyCode()==KeyEvent.VK_ENTER)
            showPage();
        
    }

    private void showPage() {
        try {
            
            String url_str = url_text.getText();
            URL url = new URL(url_str);
            
            InputStream in = url.openConnection().getInputStream();//url.openStream();
            
            page_content.setText("");
            
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            String text = new String(buf,0,len,"utf-8");
            
            page_content.setText(text);
            
            in.close();
            
            
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

}

 

posted @ 2015-11-28 20:14  幻奕  阅读(172)  评论(0编辑  收藏  举报