Java网络编程小结

网络编程

  1. 端口的概念
    数据的发送需要逻辑端口,端口是用于标识进程的逻辑地址。
    端口数字范围:0-65535(short的范围)。
    其中 0-1024 是系统使用或保留的端口。

  2. 网络模型:
    OSI参考模型 :分成7层
      应用层   –将数据先封装。有应用层的特征。依次往下加每一层的特征。
      表示层
      会话层
      传输层   –特征加到这里,将数据信息打包完。开始往下发
      网络层   –给数据信息加IP地址。
      数据链路层 –确定通过什么传输方式传输
      物理层   –通过网线等设备发送出去。到达另一个机器的主机时,反向拆包得到数据。

    TCP/IP参考模型 :分为四层
      应用层    –合并OSI中的前三个层
      传输层
      网际层
      主机至网络层 –合并OSI中的后两个层

  3. IP地址:是网络中的设备标识。
      本地地址 127.0.0.1 主机名:localhost。
      IP地址不易记忆,所以一般会给IP取名。

  4. InetAddress : 互联网协议地址。
    此类不可以 new 对象,可通过类中方法返回一个对象。
    常用方法:

    static InetAddress  getLocalHost()  //获取主机名加主机地址,可以返回本类对象
    static InetAddress  getByName()     //通过主机名获取IP地址
    String  getHostAddress()            //获取主机IP地址
    String  getHostName()               //获取主机名称
    

    举例:

    import java.net.*;
    class Demo {
        public static void main(String [] args) {
            try  {
                InetAddress iad=InetAddress.getLocalHost();
                System.out.println(iad.toString()); 
                System.out.println(iad.getHostName());      //获取主机名
                System.out.println(iad.getHostAddress());   //获取主机地址
    
                InetAddress iad2=InetAddress.getByName("www.nowup.net");
                System.out.println(iad2.getHostName()); 
                System.out.println(iad2.getHostAddress());
            }
            catch (UnknownHostException e) { throw new RuntimeException("找不到主机地址!"); }
        }
    }

    注意:
    InetAddress 要抛未知主机异常, InetAddress.toString()方法就是getHostName()和getHostAddress().
    以IP地址为目的比较方便。如果以域名为目的,需要解析过程。而且返回的IP对象可能不唯一。
    如果IP地址和对应主机名没有在网络上,则只能找到地址,但解析不了主机名。

  5. 通讯协议
    通讯规则一般有两种,UDP协议、TCP协议

    (1)UDP:
    面向无连接,不需要建立连接,所以是不可靠协议。只管将数据打包发出,接收不接受无所谓。
    速度比较快,省略了接受端确认的过程。
    每次发送数据包的大小不得超过64K。
    当数据只是瞬间存在的时候,选择使用UDP速度快。如远程视频,网络会议,步话机,广播,丢包不影响。

    实现UDP传输需要两个类, DatagramPacket , DatagramSocket 。

    DatagramPacket :
    用于将数据封包;

    构造方法:

    DatagramPacket(byte[] b,len)
    DatagramPacket(byte[] b,len,InetAddress,port)
    

    常用方法:

    InetAddress getAddress()    //返回机器的IP地址
    byte[]  getData()           //返回数据缓冲区
    int    getLength()          //获取数据长度
    int    getPort()            //获取数据端口
    void  setAddress(address)   //设置IP地址
    void  setLength(len)        //设置长度
    void  setPort(port)         //设置端口
    

    DatagramSocket :
    用于发送和接收封装好的数据包。

    构造方法:

    DatagramSocket()            //构造空端口的套接字
    DatagramSocket(port)    //构造指定端口的套接字
    

    常用方法:

    void close()            //关闭套接字
    int getPort()           //获取端口
    void disconnect()       //断开连接
    void connect(InetAddress,port)      //与指定地址和端口连接
    void receive(DatagramPacket dp)     //接收数据包
    void send(DatagramPacket dp)        //发送数据包
    InetAddress getInetAddress()        //返回套接字连接的地址
    

    举例:
    通过UDP传输方式,将一段文字数据发送出去。然后定义一个程序用于接收UDP协议传输的数据并处理。

    import java.net.*;
    class SendDemo  {   //发送端
        public static void main(String [] args) throws Exception {
            //通过DatagramSocket对象创建UDP发送服务,指定发送端口。
            DatagramSocket ds=new DatagramSocket(1234);
    
            byte [] b="aaaa".getBytes();        //将字符串变成字节数组,等待封装发送。
    
            //用DatagramPacket将数据封包。指定要发送的内容,发送地址,端口。
            DatagramPacket dp=new DatagramPacket(b,b.length,InetAddress.getByName("10.2.56.38"),5678);
    
            ds.send(dp);        //通过Socket服务的send方法,将数据包发送出去。
            ds.close();         //关闭资源。
        }
    }
    
    class ReceiveDemo {   //接收端
        public static void main(String [] args) throws Exception {
            //创建UDP Socket,建立接收端点。括号内指定端点
            DatagramSocket ds=new DatagramSocket(5678);
    
            byte [] b=new byte [1024];
    
            //存储数据的数据包。
            DatagramPacket dp=new DatagramPacket(b,b.length);   
    
            ds.receive(dp);     //通过UDP的receive方法将收到的数据存到数据包中。
            String ip=dp.getAddress().getHostAddress();
            String s=new String(dp.getData(),0,dp.getLength());
            int port=dp.getPort();
            System.out.println(ip+"::::"+s+"::::"+port);
            ds.close();     //关闭资源
        }
    }

    (2)TCP :
    必须要建立连接,形成传输数据的通道。在连接中进行大数据量传输。
    通过三次握手完成连接,是可靠协议。但效率偏低。
    (三次握手:1.发送确认请求【你在吗】2.接收请求后回复【我在】3.接收回复后确认【好,知道了】)
    下载的数据不可以丢包。要使用TCP。打电话也是TCP。建立通道才可以对话。

    实现TCP传输需要两个类, Socket , ServerSocket 。

    Socket:
    为网络服务提供的一种机制。套接字,可理解为入口。
    通信的两端都要有Socket。数据在两个Socket间通过IO传输。网络通信其实就是Socket间的通信。

    构造方法:

    Socket()                    //创建未连接套接字
    Socket(InetAddress,port)    //创建指定IP和端口的套接字
    

    常用方法:

    void close()            //关闭套接字
    void connect(SocketAddress sa)      //将此套接字连接到服务器
    InetAddress getInetAddress()        //获取套接字连接的地址
    InputStream getInputStream()        //获取套接字的输入流
    OutputStream getOutputStream()      //获取套接字的输出流
    

    ServerSocket :
    服务器套接字。

    构造方法:

    ServerSocket()              //创建未绑定的服务器套接字
    ServerSocket(port)          //创建指定端口的服务器套接字
    ServerSocket(port,backlog)  //创建指定端口和连接容量的服务器套接字
    ServerSocket(port,backlog,InetAddress)  //创建指定端口和要绑定的IP地址和容量的服务器套接字
    

    常用方法:

    Socket accept()     //接收此套接字的连接
    void close()        //关闭套接字
    InetAddress getInetAddress()    //返回服务器套接字的地址
    

    举例一:客户端发送数据,被服务端接收

    import java.io.*;
    import java.net.*;
    class ClientDemo {      //客户端
        public static void main(String [] args) {
            try  {
                //创建Socket服务,指定要连接的目的主机和端口
                Socket s=new Socket(InetAddress.getLocalHost().getHostAddress(),9090);
    
                //将数据写入到Socket流中的输出流
                OutputStream os=s.getOutputStream();
                os.write("tcp gemen laile".getBytes());
                s.close();
            }
            catch (UnknownHostException e) {    throw new RuntimeException("未知主机!");    }
            catch (IOException e) { throw new RuntimeException("连接客户端错误!"); }
        }
    }
    
    class ServerDemo    {   //服务端
        public static void main(String [] args) {
            try  {  
                //建立服务端Socket服务,并监听一个端口。
                ServerSocket ss=new ServerSocket(9090);
    
                Socket s=ss.accept();       //通过accept方法获取链接过来的客户端对象。
                System.out.println(s.getInetAddress().getHostAddress());
    
                //获取客户端发过来的数据
                InputStream is=s.getInputStream();   
    
                byte [] buf=new byte [1024];
                int len=is.read(buf);
                System.out.println(new String (buf,0,len));
                s.close();      //关闭客户端连接。
            }
            catch (IOException e)   { throw new RuntimeException("连接错误!"); }
        }
    }

    举例二:使用TCP服务实现文本大写转换。

    import java.io.*;
    import java.net.*;
    class Demo {        //客户端
        public static void main(String [] args) {
            BufferedReader in=null;
            try  {
                Socket s=new Socket(InetAddress.getLocalHost().getHostAddress(),9876);
                in=new BufferedReader(new InputStreamReader(System.in));
    
                //将数据写到Socket输出流
                PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
    
                //接收服务端发回的Socket输入流
                BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
    
                String line=null;
                while ((line=in.readLine())!=null) {
                    if ("over".equals(line))
                        break;
                    pw.println(line);
                    System.out.println("Upper:"+br.readLine());
                }
                s.close();
            }
            catch (IOException e)   { throw new RuntimeException("连接失败!"); }
            finally  {
                if (in!=null)
                    try { in.close(); }  catch (IOException e) {    throw new RuntimeException("读取失败!");    }
            }
        }
    }
    
    class Demo {    //服务端
        public static void main(String [] args) {
            try  {
                ServerSocket ss=new ServerSocket(9876);
                Socket s=ss.accept();
                System.out.println(s.getInetAddress().getHostAddress());
    
                //读取客户端发来的数据
                BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
    
                //输出数据给客户端,TRUE代表可以自动刷新
                PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
    
                String line=null;
                while ((line=br.readLine())!=null) {
                    System.out.println(line);
                    pw.println(line.toUpperCase());
                }
                s.close();
                ss.close();
            }
            catch (IOException e)   { throw new RuntimeException("等待连接错误!"); }
        }
    }

    举例三:通过TCP服务实现多线程上传图片文件到服务器。

    import java.io.*;
    import java.net.*;
    class Demo {
        public static void main(String [] args) {
            try  {
                ServerSocket ss=new ServerSocket(11111);
                while (true) {
                    Socket s=ss.accept();
                    new Thread(new PicThread(s)).start();
                }
            }
            catch (IOException e)   { throw new RuntimeException("等待连接失败了"); }
        }
    }
    
    class PicThread implements Runnable {
        private Socket s;
        PicThread(Socket s) {
            this.s=s;
        }
        public void run() {             
            String ip=s.getInetAddress().getHostAddress();
            try  {
                System.out.println(ip+"connected");
                InputStream in=s.getInputStream();
                FileOutputStream fos=new FileOutputStream("ss.jpg");
                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 (IOException e)   { throw new RuntimeException(ip+"上传失败!"); }
        }
    }
    
    class Client {
        public static void main(String [] args) {
            try  {
                if (args.length==0) {
                    System.out.println("请选择一张照片");          //主函数的数组中没有传值的话,长度就是0.报出提示。
                    return;
                } 
                File file=new File(args[0]);
                if (!(file.exists() && file.isFile())) {
                    System.out.println("文件不存在或不是文件格式"); //判断文件存在和是不是文件
                    return;
                }
                if (!(file.getName().endsWith(".jpg") || file.getName().endsWith(".bmp"))) {
                    System.out.println("图片格式不对,重新选择");      //判断文件格式
                    return;
                }
                if (file.length()>1024*1024*5) {
                    System.out.println("文件过大,请重选!");                    //判断文件大小是否合适
                    return;
                }
                Socket s=new Socket(InetAddress.getLocalHost().getHostAddress(),11111);
                File file=new File("1.jpg");
                if (!file.exists())
                    throw new RuntimeException("文件读取失败了");
                FileInputStream fis=new FileInputStream(file);
                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 [] b=new byte [1024];
                int num=in.read(b);
                System.out.println(new String (b,0,num));
                fis.close();
                s.close();
            }
            catch (IOException e)   { throw new RuntimeException("服务器连接失败了"); }
        }
    }

    注意:同一用户上传的同名文件可以判断报错。不同用户上传同名文件因为IP不同所以不同。

  6. 浏览器与客户端
    (1) 并发登录举例:
    客户端录入用户名,服务端对其校验。若名存在,则显示已登录。并在客户端显示 “welcome” 登录。
    若服务端不存在此名,在服务端显示名+loading,并在客户端显示**正在登录。
    最多登录三次,就结束。

    import java.io.*;
    import java.net.*;
    class Client {
        public static void main(String [] args) {
            try  {
                Socket s=new Socket(InetAddress.getLocalHost().getHostAddress(),11222);
                BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
                PrintWriter out=new PrintWriter(s.getOutputStream(),true);
                BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
    
                for (int x=0;x<3;x++) {
                    String line=sin.readLine();
                    if (line==null)     //不录入了,就结束
                        break;
                    out.println(line);
                    String info=br.readLine();
                    System.out.println("tip::"+info);
                    if (info.contains("welcome"))   //服务端返回welcome了,就是已经登录成功,可以结束
                        break;
                }
                sin.close();
                s.close();
            }
            catch (IOException e)   { throw new RuntimeException("与服务器连接失败"); }
        }
    }
    
    class Server {
        public static void main(String [] args) {
            try {
                ServerSocket ss=new ServerSocket(11222);
                while (true) {
                    Socket s=ss.accept();
                    new Thread(new UserThread(s)).start();
                }
            }
            catch (IOException e)   { throw new RuntimeException("等待连接失败"); }
        }
    }
    
    class UserThread implements Runnable {
        private Socket s;
        UserThread(Socket s) {
            this.s=s;
        }
        public void run() {
            String ip=s.getInetAddress().getHostAddress();
            System.out.println(ip);
            try  {
                for (int x=0;x<3;x++) {
                    BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
                    String name=br.readLine();
                    if (name==null)
                        break;
                    BufferedReader bufr=new BufferedReader(new FileReader("user.txt"));
                    PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    
                    String line=null;
                    boolean bool=false;
                    while ((line=bufr.readLine())!=null) {
                        if (line.equals(name)) {
                            bool=true;
                            break;
                        }
                    }
                    if (bool) {
                        System.out.println(name+"已登录");
                        out.println(name+", welcome");
                    }
                    else {
                        System.out.println(name+"   loading");
                        out.println(name+" 不存在");
                    }
                }
                s.close();
            }
            catch (IOException e)   { throw new RuntimeException(ip+"校验失败"); }
        }
    }
    

    (2)浏览器客户端 - - 自定义服务端
    给访问它的客户端返回一个消息即可。

    import java.io.*;
    import java.net.*;
    class Demo {
        public static void main(String [] args) {
            try  {
                ServerSocket ss=new ServerSocket(11223);
                Socket s=ss.accept();
                System.out.println(s.getInetAddress().getHostAddress());
                PrintWriter out=new PrintWriter(s.getOutputStream(),true);
                out.println("<font color='red' size='8'>客户端你好啊--我是本机服务端</font>");
                s.close();
                ss.close();
            }
            catch (IOException e)   { throw new RuntimeException("dengdailianjieshibai"); }
        }
    }
    

    (3)演示浏览器和tomcat服务器。

    import java.io.*;
    import java.net.*;
    class Demo {
        public static void main(String []args) {
            try  {
                ServerSocket ss=new ServerSocket(9988);
                Socket s=ss.accept();
                System.out.println(s.getInetAddress().getHostAddress());
                InputStream in=s.getInputStream();
                byte [] buf=new byte [1024];
                int len=in.read(buf);
                System.out.println(new String (buf,0,len));
                PrintWriter out=new PrintWriter(s.getOutputStream(),true);
                out.println("<font color='red' size='9'>客户端你好</font>");
                s.close();
                ss.close();
            }
            catch (IOException e) { throw new RuntimeException("等待连接失败!"); }
        }
    }
    
    class MyClient {        //自定义的客户端浏览器,需要启动Apache服务器
        public static void main(String []args) {
            try  {
                String ip=InetAddress.getLocalHost().getHostAddress();
                Socket s=new Socket(ip,9876);
                PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    
                //定义客户端浏览器的消息头
                out.println("GET / HTTP/1.1");              
                out.println("Accept: +++");
                out.println("Accept-Language: zh-cn");
                out.println("Host: \""+ip+"\":9988");
                out.println("Connection: closed");
    
                out.println();
                out.println();
                BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
                String line=null;
                while ((line=br.readLine())!=null) {
                    System.out.println(line);
                }
                s.close();
            }
            catch (IOException e)   { throw new RuntimeException("连接失败!"); }
        }
    }   

    (4)自定义图形界面浏览器的客户端。

    import java.io.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.net.*;
    class Demo {
        private Frame f;
        private TextField tf;
        private Button b;
        private TextArea ta;
    
        Demo() {
            init();
        } 
    
        public void init() {
            f=new Frame("我的浏览器");
            f.setBounds(150,50,999,666);
            f.setLayout(new FlowLayout());
    
            tf=new TextField(90);
            b=new Button("转到");
            ta=new TextArea(25,100);
    
            f.add(tf);
            f.add(b);
            f.add(ta);
    
            myEvent();
            f.setVisible(true);
        }
        private void myEvent() {
            tf.addKeyListener(new KeyAdapter(){
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode()==KeyEvent.VK_ENTER)
                        show();
                }
            });
            b.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e) {
                    show();
                }
            });
            f.addWindowListener(new WindowAdapter(){
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
        }
        private void show() {
            ta.setText("");
            String link=tf.getText();    
            int indexHost=link.indexOf("//"+2);
            int indexDir=link.indexOf("/",indexHost);
            String host=link.substring(indexHost,indexDir);
            String path=link.substring(indexDir); 
            String [] arr=host.split(":");
            String ip=arr[0];
            int port=Integer.parseInt(arr[1]);      //arr[1]是字符串,后面不加基数指的是转成十进制。
    
            try  {
                String ipadd=InetAddress.getLocalHost().getHostAddress();
                Socket s=new Socket(ipadd,9876);
                PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    
                //定义客户端浏览器的消息头
                out.println("GET / HTTP/1.1");              
                out.println("Accept: +++");
                out.println("Accept-Language: zh-cn");
                out.println("Host: \""+ipadd+"\":9988");
                out.println("Connection: closed");
    
                out.println();
                out.println();
    
                BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
                String line=null;
                while ((line=br.readLine())!=null) {
                    ta.append(line+"\r\n");
                }
                s.close();
            }
            catch (IOException e) { throw new RuntimeException("连接失败!"); }
        }
    
        public static void main(String [] args) {
            new Demo();
        }
    }
  7. URL 和 URLConnection
    (1)URL:
    统一资源定位符

    构造方法:

    URL(String url)         //根据指定URL形式字符串创建URL对象
    URL(String protocol, host, port, file)  //根据指定协议,主机,端口,文件创建URL对象
    

    常用方法:

    int getPort()           //获取端口,如URL没有指定端口,就返回-1.
    String getProtocol()    //获取协议
    String getHost()        //获取主机名
    String getPath()        //获取路径
    String getQuery()       //获取查询部分
    String getFile()        //获取路径和查询部分
    URLConnection operConnection()      //返回一个URLConnection 对象,表示到 URL 所引用的远程对象的连接
    

    (2)URLConnection:
    抽象的类,可以直接连接此子类对象指定的 URL ,而不用使用 Socket 连接了,因为该类内部封装了Socket协议。

    常用方法:

    InputStream getInputStream()
    OutputStream getOutputStream()
    

    举例:

    import java.io.*;
    import java.net.*;
    class Demo {
        public static void main(String [] args) {
            try {
                URL url=new URL("http://192.168.1.191/myweb/demo.html");
                URLConnection uc=url.openConnection();
                System.out.println(uc);
                InputStream in=uc.getInputStream();
                byte [] b=new byte [1024];
                int len=in.read(b);
                System.out.println(new String (b,0,len));           //如果读取成功,内容是没有响应头的
            }
            catch (IOException e) { throw new RuntimeException("连接错误!"); }
        }
    }
    

    举例:
    使用URL实现自定义浏览器的简化。

    import java.io.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.net.*;
    class Demo {
        private Frame f;
        private TextField tf;
        private Button b;
        private TextArea ta;
        Demo() {
            init();
        }
        public void init() {
            f=new Frame("我的浏览器");
            f.setBounds(150,50,999,666);
            f.setLayout(new FlowLayout());
            tf=new TextField(90);
            b=new Button("转到");
            ta=new TextArea(25,100);
            f.add(tf);
            f.add(b);
            f.add(ta);
            myEvent();
            f.setVisible(true);
        }
        private void myEvent() {
            tf.addKeyListener(new KeyAdapter(){
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode()==KeyEvent.VK_ENTER)
                        show();
                }
            }); 
            b.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e) {
                    show();
                }
            }); 
            f.addWindowListener(new WindowAdapter(){
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
        }
        private void show() {
            ta.setText("");
            String link=tf.getText();    
            try  {
                URL url=new URL(link);
                URLConnection uc=url.openConnection();
    
                InputStream in=uc.getInputStream();
                byte [] b=new byte [1024];
                int len=in.read(b);
                ta.setText(new String(b,0,len));
            }
            catch (IOException e)   { throw new RuntimeException("连接错误!"); }
        }
    
        public static void main(String [] args) {
            new Demo();
        }
    }
  8. 域名解析
    将域名翻译成IP地址。DNS服务器
    浏览器先拿域名去找DNS服务器,DNS返回一个域名对应的IP地址。浏览器再拿这个IP地址去找对应主机

    如果是找本机,直接localhost或者127.0.0.1.
    它俩的映射关系就在本机。

    当访问主机时,浏览器先找的是本地host,再去DNS上找。
    如果不详访问某个网站或者达到一定目的时,可以在本地host文件上添加指定域名指向本地或具体IP,可以按照host中的内容规则访问。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值