网络编程(二)

服务器端多线程技术

应用java的多线程技术可以实现多个客户端向服务器端上传文件:
客户端:

public class UploadClient {

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

        //1. 创建socket客户端对象
        Socket s=new Socket("127.0.0.1",10005);

        //2. 读取图片文件
        FileInputStream fis=new FileInputStream("F:\\1.jpg");
        BufferedInputStream bufis=new BufferedInputStream(fis);

        //3.获取socket输出流,将读到图片发送给服务器端
        OutputStream  out=s.getOutputStream();


        int ch=0;
        while((ch=bufis.read())!=-1){
            out.write(ch);
        }
        //告知服务端数据发送完毕
        s.shutdownOutput();

        //读取服务端发回的上传成功
        BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str=bufIn.readLine();
        System.out.println(str);

        bufis.close();
        s.close();
    }

}

服务器端:

public class UploadServer {

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

        //1. 创建serversocket服务
        ServerSocket ss=new ServerSocket(10005);

        while(true){//不断接收客户端

        //2. 获取客户端
        Socket s=ss.accept();


        new Thread(new UploadTask(s)).start();


        }
//      ss.close();
    }

}

服务器端线程处理类:

public class UploadTask implements Runnable {

    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{

            //3. 读取客户端发过来的数据(源)
            BufferedInputStream bufIn=new BufferedInputStream(s.getInputStream());

            //4. 写出到服务端的文件中(目的)
            File dir=new File("f:\\pic");
            if(!dir.exists())
                dir.mkdirs();

            File file=new File(dir,ip+".jpg");
            //如果文件已经存在于服务器端
            while(file.exists())
                file=new File(dir,ip+"("+(++count)+").jpg");

            BufferedOutputStream bufw=new BufferedOutputStream(new FileOutputStream(file));

            int line=0;
            while((line=bufIn.read())!=-1){
                bufw.write(line);

            }

            //5. 告知客户端上传成功
            PrintWriter out=new PrintWriter(s.getOutputStream(),true);
            out.println("上传成功");

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

            }
    }

}

客户端和服务器端原理

常见的客户端有IE浏览器。常见的服务器端有tomcat,它是一种web服务器。

服务器端原理

自定义服务端,使用已有的客户端IE,了解客户端给服务器端发了什么请求。
准备工作:首先电脑里要装tomcat服务器,再在webapps创建目录myweb,在myweb里创建文件1.html。
自定义服务器端:

public class MyTomat {

    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'>welcome to chengdu</font>");

        s.close();
        ss.close();

    }

}

客户端给服务器端发送的请求为:

GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:9090
Connection: Keep-Alive

这些消息分成三个部分:请求行,请求消息头,请求体。
GET / HTTP/1.1是请求行,包含三部分内容:1. 请求方式(get/post) 2. myweb/1.html 请求的资源路径 3. http协议版本

请求消息头的格式:属性名:属性值


Accept: text/html, application/xhtml+xml, image/jxr, */*  //能够解析的数据类型
Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3  //支持的语言
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko  //一些用户信息,系统版本等
Accept-Encoding: gzip, deflate //支持的压缩方式
Host: 127.0.0.1:9090 //访问的主机
Connection: Keep-Alive

请求体是自定义的信息。请求头和请求体之间必须有一行空行。
此时IE浏览器显示的内容为:
这里写图片描述

客户端原理

自定义一个浏览器,使用已有的服务器,了解服务器端给客户端端发了什么请求。
自定义浏览器:

public class MyBrowser {

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

        Socket s=new Socket("127.0.0.1",8080);


        //模拟浏览器,给tomcat服务端发送符合http协议的请求消息
        PrintWriter out=new PrintWriter(s.getOutputStream(),true);
        out.println("GET /myweb/1.html HTTP/1.1");
        out.println("Accept: text/html, application/xhtml+xml, image/jxr, */*");
        out.println("Host: 127.0.0.1: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/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"189-1511429543426"
Last-Modified: Thu, 23 Nov 2017 09:32:23 GMT
Content-Type: text/html
Content-Length: 189
Date: Fri, 24 Nov 2017 02:34:55 GMT
Connection: close

<html>
    <head>
        <title>it's my page</title>
    <head>

    <body>
        <h1>welcome to my page</h1>

        <font size='5' color ='red'>html webpage source in tomcat</font>
    </body>
</html>

第一行HTTP/1.1 200 OK 是应答行,由三部分内容组成:1. http的协议版本 2. 应答状态码(200表示成功,404表示not found) 3. 应答状态描述信息。

应答消息属性信息。格式为 属性名:属性值

Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"189-1511429543426"
Last-Modified: Thu, 23 Nov 2017 09:32:23 GMT
Content-Type: text/html
Content-Length: 189
Date: Thu, 23 Nov 2017 09:33:06 GMT
Connection: close

再是应答消息体:

<html>
    <head>
        <title>it's my page</title>
    <head>

    <body>
        <h1>welcome to my page</h1>

        <font size='5' color ='red'>html webpage source in tomcat</font>
    </body>
</html>

应答消息属性信息(应答头)和应答体之间有一行空行。

URL类

在我们自己模拟的浏览器中,服务器返回的应答消息包含应答行,应答消息头,应答体三个部分的信息,但是在真正的浏览器里,我们却只看到应答体部分的信息,这是由于浏览器自身具备解析http协议的能力,在应用层具备一个解析引擎,所以浏览器将应答消息头的部分给解析了,又在应答消息头解析的时候看到了应答消息体的解析方式,所以把应答消息体也解析为我们在浏览器中看到的样子,而不是HTML文本。

我们也可以自定义一个类似的解析引擎,将应答消息头解析。
URL地址包含着很多信息,可以封装成一个对象来解析,获取协议、端口、ip地址等等信息。

URL代表统一资源定位符,是一种URI(统一资源标识符),URI还包含URN(同一资源名称)。
URL不仅可以获取协议、端口等等信息,还可以通过openStream方法打开此URL的连接并返回一个用于从该连接读入的InputStream。通过这个就可以将应答消息解析掉。

public class URLDemo {

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

        String str_url="http://127.0.0.1:8080/myweb/1.html?name=lisa";

        URL url=new URL(str_url);

//      getInfo(url);

        InputStream in=url.openStream();//原理url.openConnection().getInputStream();

        //获取URL对象的URL连接器对象。将连接封装成了对象,这个对象就是java内置的可以解析的具体协议的对象+socket
//      URLConnection conn =url.openConnection();
//      InputStream in=conn.getInputStream();

//      System.out.println(conn);//sun.net.www.protocol.http.HttpURLConnection:http://127.0.0.1:8080/myweb/1.html?name=lisa
//      
//      String value=conn.getHeaderField("Content-Type");//文本类型
//      System.out.println(value);//text/html 启动指定的解析器来解析数据
//      

        byte[] buf=new byte[1024];

        int len=in.read(buf);

        String text=new String(buf,0,len);
        System.out.println(text);

        in.close();

    }

    /**
     * @param url
     */
    public static void getInfo(URL 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());
    }

}

输出的是:

<html>
    <head>
        <title>it's my page</title>
    <head>

    <body>
        <h1>welcome to my page</h1>

        <font size='5' color ='red'>html webpage source in tomcat</font>
    </body>
</html>

只有应答体了。

常见的网络结构

  1. C/S client/server
    特点:该结构的软件,客户端和服务端都需要编写。
    缺点:开发成本较高,维护较为麻烦。
    优点:客户端在本地可以分担一部分运算。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值