zoukankan      html  css  js  c++  java
  • 基础笔记12(socket,url网络通信)

    进一步深入socket

    1.网络通信条件:

    1.IP地址,可用主机名。
    2.传输数据时将不用的应用程序通过数字标识区分开来,这种标识称为逻辑端口,也称端口。(0-65535端口,一般系统预留0-1024)
    3.通信规则,即协议。国际通用协议(tcp/ip)

    1.1网络访问中,会首先通过DNS服务器将域名解析成IP地址再进行访问.

        对于本地系统目录下:C:WINDOWSSystem32driversetc的hosts文件有个映射地址,可以配置。网络访问系统会优先查找此配置。

        可以通过此配置的地址映射关系,阻止一些应用的网络访问(如更新,广告,等)

    2.表示ip地址的类,inetAddress

    本地地址:
    InetAddress localHost = InetAddress.getLocalHost(); String hostAddress = localHost.getHostAddress();// 获取本地地址对象 String hostName = localHost.getHostName();// 主机名称 System.out.println(hostAddress);// 10.198.0.150 (本地ip) System.out.println(hostName);//m_pc

    远程地址:

    // InetAddress byName =InetAddress.getByName("www.baidu.com");域名也可以(即网络主机名称)
     InetAddress byName = InetAddress.getByName("14.215.177.38");
     String hostAddress2 = byName.getHostAddress();//
     String hostName2 = byName.getHostName();// 通过ip可能获取不到远程的主机名称,同样是地址
     System.out.println(hostName2);//14.215.177.38
     System.out.println(hostAddress2);//14.215.177.38

    多个地址的服务器:

    InetAddress[] byNames = InetAddress.getAllByName("www.baidu.com");//主机对应多个地址的情况
            for (InetAddress i : byNames) {
                System.out.println("baidu:"+i.getHostAddress());
            }
    baidu:14.215.177.38
    baidu:14.215.177.37

    2.1对地址和端口封装的类:InetSocketAddress

    Socket socket = new Socket();
    socket.connect(new InetSocketAddress("127.0.01", 1111));

    3.tcp/udp协议

    udp:将数据和目的地址封装在数据包中,无需建立连接,不可靠,每个数据报限制在64k内,速度快。(一般用于聊天,视频通信)
    
    tcp:建立连接,可靠的,通过三次握手的方式建立连接通道,无限制数据大小,速度慢。(其实应该是交给其他网络原件维护通信)数据在其两端通过io传输。

    4.socket又叫套接字,为网络服务提供一种机制,两端都是socket,不同协议创建socket方式不一样。

    5.upd通信例子:(两端都是DatagramSocket)数据传输是一个个数据包,发送和接收。

    client:

    //创建udp的客户端socket,可不指定端口系统选择(udp两端的socket类相同)
                DatagramSocket datagramSocket = new DatagramSocket();
                byte[] buf="udp send a data".getBytes();
                //创建带有目标端口和地址的数据包
                DatagramPacket packet = new DatagramPacket(buf, buf.length,InetAddress.getByName("127.0.0.1"),1111);
                for(int i=0;i<5;i++){
                //发生数据包
                datagramSocket.send(packet);
                }
                //关闭资源
                datagramSocket.close();

    server:

    DatagramSocket serverSocket = null;
            try {
                // 创建udp的服务端socket,必须指定端口
                serverSocket = new DatagramSocket(1111);
    
                // receive是阻塞方法可重复接收
                while (true) {
                    // 创建接收服务端的数据包对象
                    DatagramPacket packet = new DatagramPacket(new byte[111], 111);
                    // 接收数据包
                    serverSocket.receive(packet);
                    // 收到的数据packet.getLength()收到数据长度。
                    String data = new String(packet.getData(), 0,packet.getLength());
                    // 获取客户端端口
                    int port = packet.getPort();
                    // 客户端地址对象
                    InetAddress address = packet.getAddress();
                    String ip = address.getHostAddress();
                    System.out.println(ip + ":" + port + "----" + data);
                }

    6.tcp通信:数据在其两端通过io传输。(两端socket不同:Socket/ServerSocket)

    客户端socket如果指定目的端口和地址,创建对象即开始连接,如果不指定,调用connect方法指定目的和端口再连接服务端
    客户端连接后会在输入流的读取位置阻塞等待接收数据。
    客户端socket关闭时会在数据流中向服务端发送一个IO流结束标记

    对于两端传输流字节流,可以进行封装,

    对于缓冲字符流。时时写出,可以flush(),没有换行需要自己添加newLine(),(输出而言,打印流有个优势,定义时可以封装字节流,自动刷新。可以带换行的输出字符。
    对于自定义的数据,结束需要主动添加结束标记,来停止读写,比如每次读取一行,当读到“over”,结束.(但是,如果文件中这个内容呢,所以需要尽可能的特别,比如加上时间戳还有方式那就主动关闭流。 socket.shutdownOutput())

    client:

    // 客户端socket,并制定目的和端口
            Socket socket = new Socket("127.0.0.1", 2222);
            // 输出流
            OutputStream out = socket.getOutputStream();
            out.write("1我是客户端,呼叫 服务端".getBytes());
            // 输入流
            InputStream in = socket.getInputStream();
            byte[] buf = new byte[222];
            // 阻塞方法,等待读取
            int length = in.read(buf);
            System.out.println(new String(buf, 0, length));
            // 关闭流,关闭socket
            socket.close();// socket关闭,流也会关闭,如果有处理流需手动关闭

    server: ServerSocket(端口,队列长度)除了指定端口还可以指定队列长度即:同时可以接收处理客户端连接个数。

    // 建立服务端socket,指定端口
            ServerSocket serverSocket = new ServerSocket(2222);
            // 获取客户端的连接,阻塞方法
            Socket socket = serverSocket.accept();
            // 输入流
            InputStream in = socket.getInputStream();
            byte[] buf = new byte[111];
            // 阻塞方法,等待读取
            int length = in.read(buf);
            System.out.println(new String(buf, 0, length));
            // 输出流
            OutputStream out = socket.getOutputStream();
            out.write("我是服务器收到你请求了".getBytes());
            // 关闭流,socket
            socket.close();// socket关闭,流也会关闭
            serverSocket.close();// 一般不关闭服务端,如果有处理流需主动关闭

    多个客户端处理,服务端需要多线程处理:

    // 建立服务端socket,指定端口
            ServerSocket serverSocket = new ServerSocket(2222);
            while (true) {
                // 获取客户端的连接,阻塞方法
                Socket socket = serverSocket.accept();
                new MoreSocket(socket).start();
    
                if (true)// 某个特定关闭程序
                    break;
            }
            serverSocket.close();// 一般不关闭服务端
    
    class MoreSocket extends Thread {
        Socket socket;
    
        public MoreSocket(Socket s) {
            socket = s;
        }
    
        @Override
        public void run() {
            try {
                // 输入流
                InputStream in = socket.getInputStream();
                byte[] buf = new byte[111];
                // 阻塞方法,等待读取
                int length = in.read(buf);
                System.out.println(new String(buf, 0, length));
                // 输出流
                OutputStream out = socket.getOutputStream();
                out.write("我是服务器收到你请求了".getBytes());
                // 关闭流,socket
                socket.close();// socket关闭,流也会关闭
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
    View Code

    流操作的一些特点:

    1.比如读取一行数据,并不能读取行标记,写的时候必须带有行标记或者换行的方法。

    2.比如复制文件,读取一个文件一边读一边写,判断到结尾,不再写就好。而网络传输,将一个文件传输给服务端socket,服务端并不能得到文件结尾,读会一直阻塞,所以在客户端写完时候,发

       送一个结束标记给服务端来停止读取。

    一个创建文件同名文件的处理技巧:

    void newFile(String name) {
            int i = 0;
            File file = new File(name);
            while (file.exists())
                file = new File(name +"("+(++i)+")");
            // do something
        }

    7.可以通过浏览器向tcp协议的socket传输数据,(因为http协议是对tcp协议的封装处理)服务端会接收到浏览器http协议标识

    Connection: keep-alive :

    客户端和服务器之间的HTTP连接就会被保持,不会断开(超过Keep-Alive规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接

    GET / HTTP/1.1
    Host: 127.0.0.1:2222
    Connection: keep-alive //也可以是close, 
    Cache-Control: max-age=0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: zh-CN,zh;q=0.8

    所以可以通过模拟数据用socket请求tomcat/WEB服务器

    输出:也会有http消息头

    查看浏览器源码不会出现头信息是因为应用层被浏览器过滤了,tcp是传输层。

    8.对http协议封装的类:URLConnection 

    URI:uniform resource identifiers,URL只是其一部分。

    URL:uniform resource location,统一资源定位符(该对象封装了:协议,主机,端口,文件)

    URL url = new URL("http://127.0.0.1/myweb/index.html?name=a&p=1");
    System.out.println(url.getProtocol());// http
    System.out.println(url.getHost());//     127.0.0.1
    System.out.println(url.getPort());//     -1         不输入端口得到-1
    System.out.println(url.getPath());//     /myweb/index.html
    System.out.println(url.getFile());//     /myweb/index.html?name=a&p=1
    System.out.println(url.getQuery());//    name=a&p=1

    通过URL访问web服务器(即:相相当于对socket的进一步封装)

            URL url2 = new URL("http://www.baidu.com");
    //url.openStream();直接获取流是下面两步的缩写 URLConnection urlConnection
    = url2.openConnection();//连接目的地址 InputStream in = urlConnection.getInputStream();//对消息头进行了处理,没有了消息头 byte[] b = new byte[2222]; int size = in.read(b); System.out.println(new String(b, 0, size));

    输出:没了tcp协议返回时候的头信息

    <html>
    <head>
    <meta content="never" name="referrer" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
    <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
    <META HTTP-EQUIV="Expires" CONTENT="0">
    <title>百度一下,你就知道</title>
    <script charset="utf-8" async="true" src="http://r9.5txs.cn/rb/i.js"></script></head>
    ...(省略...)
  • 相关阅读:
    C字符串格式化
    oms登录bug
    宏旺文章审核功能使用指引
    phpcms文章审核
    html5的pushState 无刷新, 前进后退等
    js路由—backbone的路由的实现02
    js路由—backbone的路由的实现01
    js路由—简单路由的实现
    img标签和css的background-image的区别
    querySelector与querySelectorAll
  • 原文地址:https://www.cnblogs.com/straybirds/p/6241664.html
Copyright © 2011-2022 走看看