Java基础—网络编程(二)

来源:互联网 发布:网络机顶盒哪个好用 编辑:程序博客网 时间:2024/06/05 05:22

      • 一TCP协议通信
      • 二URL类
      • 三URLConnection类
      • 四扩展知识
      • 五域名解析

网络编程(二)

一、TCP协议通信

    1.上传图片练习
      1)将图片上传到服务器端保存。

示例代码:

package com.heisejiuhuche.socket;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.net.Socket;public class PicUploadClient {    public static void main(String[] args) throws Exception {        upload();    }    private static void upload() throws Exception {        /* 创建Socket对象,指定主机和端口 */        Socket s = new Socket("localhost", 10007);        /* 创建File对象,关联文件 */        File file = new File("C://Users//jeremy//Documents//javaTmp//me.jpg");        /* 创建输入输出流对象 */        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));        BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());        int b = 0;        /* 上传文件 */        while((b = bis.read()) != -1) {            bos.write(b);            bos.flush();        }        /* 发送结束符 */        s.shutdownOutput();        /* 获取反馈信息 */        InputStream in = s.getInputStream();        byte[] buf = new byte[1024];        int msg = in.read(buf);        System.out.println(new String(buf, 0, msg));        bis.close();        s.close();    }}package com.heisejiuhuche.socket;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class PicUploadServer {    public static void main(String[] args) throws Exception {        recv();    }    private static void recv() throws Exception {        ServerSocket ss = new ServerSocket(10007);        Socket s = ss.accept();        /* 创建输入输出流对象 */        BufferedInputStream bis = new BufferedInputStream(s.getInputStream());        File file = new File("C://Users//jeremy//Documents//me.jpg");        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));        int b = 0;        /* 保存文件 */        while((b = bis.read()) != -1) {            bos.write(b);            bos.flush();        }        /*发送反馈信息 */        OutputStream out = s.getOutputStream();        out.write("上传成功".getBytes());        bos.close();        s.close();        ss.close();    }}

程序运行结果:上传成功

      2)TCP客户端并发上传图片
        这个服务端有局限性。当一个客户端连接服务器之后,因为服务器是单线程,那么其他客户端如果想连接服务器,只能带前一个客户完成所有任务,才能连接。要同时处理多个客户端请求,应该明确客户端要在服务器端要执行的代码,然后将每个客户端封装到一个线程当中,同步执行。

示例代码:

package com.heisejiuhuche.socket;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.net.Socket;public class UploadPicByThreadClient {    public static void main(String[] args) throws Exception {        /* 限制文件格式,大小等条件 */        if(args.length != 1) {            System.out.println("请指定一个jpg文件上传...");            return;        }        File file = new File(args[0]);        if(!(file.exists() && file.isFile())) {            System.out.println("文件不存在或者不是文件类型...");            return;        }        if(!(file.getName().endsWith(".jpg"))) {            System.out.println("格式不正确...");            return;        }        if(file.length() > 1024 * 1024 * 5) {            System.out.println("文件过大!");            return;        }        /* 创建Socket对象,指定主机和端口 */        Socket s = new Socket("localhost", 10007);        /* 创建File对象,关联文件 *///      File file = new File("C://Users//jeremy//Documents//javaTmp//me.jpg");        /* 创建输入输出流对象 */        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));        BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());        int b = 0;        /* 上传文件 */        while((b = bis.read()) != -1) {            bos.write(b);            bos.flush();        }        /* 发送结束符 */        s.shutdownOutput();        /* 获取反馈信息 */        InputStream in = s.getInputStream();        byte[] buf = new byte[1024];        int msg = in.read(buf);        System.out.println(new String(buf, 0, msg));        bis.close();        s.close();    }}package com.heisejiuhuche.socket;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class UploadPicByThreadServer {    public static void main(String[] args) throws Exception {        ServerSocket ss = new ServerSocket(10007);        while(true) {            Socket s = ss.accept();            new Thread(new PicServerThread(s)).start();        }    }}/* 将客户端上传的代码封装成线程 */class PicServerThread implements Runnable {    private Socket s;    PicServerThread(Socket s) {        this.s = s;    }    public void run() {        String ip = s.getInetAddress().getHostAddress();        int count = 1;        try {            System.out.println(ip + " connected..");            /* 避免文件名重复 */            File file = new File("C://Users//jeremy//Documents//" + ip + "(" + count + ")" + ".jpg");            /* 循环判断,如果文件存在,让count自增 */            while(file.exists())                file = new File("C://Users//jeremy//Documents//" + ip + "(" + count++ + ")" + ".jpg");            /* 读取文件,写入服务端 */            BufferedInputStream bis = new BufferedInputStream(s.getInputStream());            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));            int b = 0;            while((b = bis.read()) != -1) {                bos.write(b);                bos.flush();            }            OutputStream out = s.getOutputStream();            out.write("上传成功".getBytes());            bos.close();            s.close();        } catch(IOException e) {            throw new RuntimeException(ip + " 上传失败...");        }    }}

    2.检测用户名练习
      客户端通过键盘录入用户名,如果该用户存在,在服务器端显示xxx,已登录;在客户端显示xxx,欢迎光临。如果用户不存在,在服务端显示xxx,尝试登录;在客户端显示xxx,该用户不存在。

示例代码:

package com.heisejiuhuche.socket;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;public class LoginClient {    public static void main(String[] args) throws Exception {        Socket s = new Socket("localhost", 10009);        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));        PrintWriter pw = new PrintWriter(s.getOutputStream(), true);        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));        for(int x = 0; x < 3; x++) {            String line = bufr.readLine();            /* 如果输入为空,直接结束循环 */            if(line == null)                break;            /* 发送名字到服务器端 */            pw.println(line);            /* 读取回馈信息 */            String feedback = bufIn.readLine();            System.out.println(feedback);            /* 如果回馈信息有欢迎字样,结束循环 */            if(feedback.contains("欢迎"))                break;        }        bufr.close();        s.close();    }}package com.heisejiuhuche.socket;import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;public class LoginServer {    public static void main(String[] args) throws Exception {        ServerSocket ss = new ServerSocket(10009);        while(true) {            Socket s = ss.accept();            new Thread(new UserThread(s)).start();        }    }}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 + " connected...");        try {            for(int x = 0; x < 3; x++) {                BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));                String name = bufIn.readLine();                if(name == null)                    break;                /* 这一行代码一定放在for循环里面,不然readLine的指针回不到文件开端,读不到名字 */                BufferedReader bufr = new BufferedReader(new FileReader("C://Users//jeremy//Documents//javaTmp//user.txt"));                PrintWriter pw = new PrintWriter(s.getOutputStream(), true);                String line = null;                Boolean flag = false;                /* 根据flag的结果判断要进行的操作  */                while((line = bufr.readLine()) != null) {                    if(name.equals(line)) {                        flag = true;                        break;                    }                }                if(flag) {                    System.out.println(name + "已登录!");                    pw.println(name + ", 欢迎登录!");                    break;                } else {                    System.out.println(ip + "正在尝试登录...");                    pw.println(name + "不存在...");                }                bufr.close();            }            s.close();        } catch(IOException e) {            throw new RuntimeException(ip + "校验失败...");        }    }}

    3.自定义浏览器
      1)HTTP请求消息头
        请求头信息中包括了发送该请求的主机地址,端口,路径,可以接受的应用程序类型,所使用语言,封装压缩形式等信息。请求头信息示例如下:

GET / HTTP/1.1Accept: text/html, application/xhtml+xml, */*Accept-Language: en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like GeckoAccept-Encoding: gzip, deflateHost: 127.0.0.1:11000DNT: 1Connection: Keep-Alive

模拟一个浏览器,想服务器发送请求头信息,获取页面。

示例代码:

package com.heisejiuhuche.socket;import java.io.InputStream;import java.io.PrintWriter;import java.net.Socket;public class BrowserClient {    public static void main(String[] args) throws Exception {        /* 访问本机的Tomcat服务器,端口8080 */        Socket s = new Socket("localhost", 8080);        PrintWriter out = new PrintWriter(s.getOutputStream(), true);        /* 发送HTTP请求头 */        out.println("GET / HTTP/1.1");        out.println("Accept: */*");        out.println("Accept-Language: en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3");        out.println("Accept-Encoding: gzip, deflate");        out.println("Connection: closed");        /* 用空行分割请求头和请求体 */        out.println();        out.println();        /* 获取服务器返回的信息 */        InputStream in = s.getInputStream();        byte[] buf = new byte[1024];        int len = in.read(buf);        System.out.println(new String(buf, 0, len));        s.close();    }}

二、URL类

    1.概述
      URL(Uniform Resource Locator)类代表一个同一资源定位符。该类是指向互联网资源的指针。

    2.常用方法
      -String getFile():获取此URL的文件名
      -String getHost():获取此URL的主机名
      -String getPath():获取此URL的路径部分
      -int getPort():获取此URL的端口号
      -String getProtocol():获取此URL的协议名称
      -String getQuery():获取此URL的查询部

    3.常用方法演示

示例代码:

package com.heisejiuhuche.socket;import java.net.MalformedURLException;import java.net.URL;public class URLDemo {    public static void main(String[] args) throws MalformedURLException {        URL url = new URL("http://192.168.0.100:8080/myweb/index.html/?name=hsjhc&age=25");        /* 演示常用方法 */        System.out.println("getProtocol: " + url.getProtocol());        System.out.println("getHost: " + url.getHost());        System.out.println("getPort: " + url.getPort());        System.out.println("getPath: " + url.getPath());        System.out.println("getFile: " + url.getFile());        System.out.println("getQuery: " + url.getQuery());    }}

程序运行结果:

getProtocol: httpgetHost: 192.168.0.100getPort: 8080getPath: /myweb/index.html/getFile: /myweb/index.html/?name=hsjhc&age=25getQuery: name=hsjhc&age=25

注意:
没有指定端口,返回-1;开发时要进行判断,如果port的值为-1,要给port赋值为80

三、URLConnection类

    1.概述
      URLConnection类对象是URL对象调用openConnect()方法之后的返回值,就能得到这个URL的连接对象,也就是目标主机对象;获取URLConnection对象可以方便获取Socket输入流对象

    2.URLConnection类演示

示例代码:

package com.heisejiuhuche.socket;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;public class URLConnectionDemo {    public static void main(String[] args) throws Exception {        /* 封装URL对象 */        URL url = new URL("http://192.168.0.100:8080/myweb/indetml/?name=hsjhc&age=25");        /* 调用url对象的openConnection方法,得到URLConnection对象 */        URLConnection conn = url.openConnection();        System.out.println(conn);        /* 因为URLConnection对象中封装了Socket对象         * 所以可以调用getInputStream()方法获取输入流来读取服务器端数据 */        InputStream in = conn.getInputStream();        byte[] buf = new byte[1024];        int len = in.read(buf);        System.out.println(new String(buf, 0, len));    }}

注意:
url.openConnection().getInputStream()这行代码,可以简写成url.openStream();该方法是URLConnection类中获取InputStream的便捷方法

四、扩展知识

    1.Socket空参数构造函数
      通过调用connect()方法连接主机;connect()方法可以接收一个SocketAddress对象作为参数;SocketAddress类的子类InetSocketAddress类封装IP地址端口;那么以前在创建Socket对象的时候分开写主机IP和端口,现在也可以调用connect方法,传递一个InetSocketAddress对象即可。

    2.ServerSocket类接收的backlog参数
      backlog表示队列的最大长度。它代表能同时连接到服务器的最大客户端个数。在服务器端开发时,要指定这个参数,避免服务器因连接数过多而死机。

五、域名解析

    1.概述
      IP地址不容易记忆,通常人们在访问网站的时候,在地址栏输入的都是类似于www.baidu.com这样的域名。但是要访问到网络上对应这个域名的那个主机,需要将这个域名解析成IP地址。这个过程,需要DNS域名解析服务器来完成。DNS服务器中记录的是每个域名对应的IP地址映射表。

    2.基本原理

这里写图片描述

PC在访问网站的时候,要走这4步流程。在浏览器输入域名之后,第1步,到本机C盘``(C:\windows\Systems\drivers\etc\)下的hosts文件,寻找这个域名是否在本地有已经配置的IP地址,如果有,直接访问该IP,否则,进入第2步;第2步,访问公网DNS服务器,找到DNS服务器上的域名——IP映射关系;第3步,DNS服务器将对应的IP地址返回给PC;第4步,PC端访问该IP地址,找到公网上的指定主机。

注意:
127.0.0.1与localhost之间的映射关系在本机上C盘下的hosts文件中。该文件可以用于屏蔽恶意网站。

0 0