• 基础笔记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>
    ...(省略...)
  • 相关阅读:
    mysql命令集锦
    linux 删除文件名带括号的文件
    linux下的cron定时任务
    struts2文件下载的实现
    贴一贴自己写的文件监控代码python
    Service Unavailable on IIS6 Win2003 x64
    'style.cssText' is null or not an object
    "the current fsmo could not be contacted" when change rid role
    远程激活程序
    新浪图片病毒
  • 原文地址:https://www.cnblogs.com/straybirds/p/6241664.html
Copyright © 2020-2023  润新知