• 网络编程之TCP


    什么是七层协议?

    IOS(国际标准委员会组织)将数据的传递从逻辑上划分了以下七层
    应用层、表示层、会话层、传输层、网络层、数据链据层、物理层

    当发送消息时,需要按照上述从前往后的次序对发送的内容进行层层加包,最后发送出去
    当接收消息时,需要按照上述相反的次序对发送的内容进行层层拆包,最后解析出来

    常见协议

    协议:就是一种约定/规则,是通信双方需要遵循的一种机制

    http:超文本传输协议,浏览网站时使用该协议
    ftp:文件传输协议,上传下载文件时候使用该协议
    tcp:传输控制协议,是一种面向连接的协议
    udp:用户数据报协议,是一种非面向连接的协议
    ip:互联网协议,是上述协议的底层协议

    端口号

    IP地址可以定位到具体的一台设备
    端口号可以定位到设备上具体的进程
    在网络编程中需要提供:IP地址,端口号

    端口号:本质上是由16位二进制组成的整数,范围是:0~65535,其中0~1024之间的端口以及被系统占用,因此编程端口号从1025开始

    Socket

    Socket套接字:
    网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字

    Socket原理机制:
    通信的两端都有Socket
    网络通信其实就是Socket间的通信
    数据在两个Socket间通过IO传输

    InetAddress

    在JDK中提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法

    其中,前两个方法用于获得该类的实例对象,第一个方法用于获得表示指定主机的InetAddress对象,第2个方法用于获得表示本地的InetAddress对象。通过InetAddress对象便可获取指定主机名、IP地址等。

    接下来通过一个案例来演示InetAddress常用方法的使用

    import java.net.InetAddress;
    public class Example01 {
        public static void main(String[] args) throws Exception {
            InetAddress host = InetAddress.getLocalHost();
            InetAddress byName = InetAddress.getByName("www.baidu.com");
            System.out.println("本机的IP地址:"+host.getHostAddress());
            System.out.println("百度的IP地址:"+byName.getHostAddress());
            System.out.println("3秒内是否可达:"+byName.isReachable(3000));
            System.out.println("本机的主机名是:"+host.getHostName());
            System.out.println("百度的主机名是:"+byName.getHostName());
        }
    }

    TCP通信

    面向连接、安全可靠,效率稍低,通过三次握手建立连接

    在JDK中提供了两个用于实现TCP程序的类,一个是ServerSocket类,用于表示服务器端,一个Socket类,用于表示客户端。通信时,首先要创建代表服务器端ServerSocket对象,创建该对象相当于开启了一个服务,此服务会等待客户端的连接;然后创建代表客户端的Socket对象,使用该对象向服务器端发出连接请求,服务器端响应请求后,两者才建立连接,开始通信。

    ServerSocket(int port)

    使用该构造方法在创建Serversocket对象时,可以将其绑定到一个指定的端口号上(参数port就是端口号)。端口号可以指定为0,此时系统就会分配一个还没被其他网络程序所使用的的端口号。由于客户端需要指定的端口号来访问服务器端程序,因此端口号随机分配的情况并不常用,通常都会让服务器端程序监听一个指定的端口号。

    ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求时,accept()方法才会返回一个Socket对象,用于和客户端实现通信

    Socket(InetAddress address,int port)

    参数address用于接收一个InetAddress 类型的对象,该对象用于封装一个IP地址

    Socket类的常用方法,其中,getInputStream()和getOutputStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。

    接下来通过一张图来描述服务器端和客户端的数据传输

    简单的TCP网络程序

    通过前面两个小节了解到ServerSocket、Socket类的基本用法。为了让初学者更好地掌握这两个类的使用,接下来通过一个TCP通信的案例来进一步学习这两个类的用法

    要实现TCP通信需要创建一个服务器端程序和一个客户端程序,为了保证数据传输的安全,首先需要实现服务端程序。

    建立TCP服务端的思路

      1. 创建ServerSocket类的想,并提供端口号
      2. 等待客户端连接,使用accept()方法
      3. 等Socket对象,并使用输入输出流进行通信
      4. 关闭相互资源

    public class Server {
        private static final int PORT=8888;        //定义一个端口号
        public static void main(String[] args) throws Exception {
            //创建ServerSocket对象
            ServerSocket ss = new ServerSocket(PORT);  
            //调用accpet()等待客户端的连接
            Socket s = ss.accept();        
            //获取客户端的输出流
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
            System.out.println("开始与客户端交互数据");    
            //当客户端接入后,向客户端输出数据
            bw.write("我是服务器,你好客户端!"); 
            //模拟置信其他功能占用的时间
            Thread.sleep(5000);         
            System.out.println("结束与客户端交互数据");
            bw.flush();
            s.close();
            bw.close();
        }
    }

    在创建ServerSocket对象时指定了端口号,并调用该对象的accept()方法。从运行结果可以看出,控制台中的光标一直在闪动,这是因为accept()方法发生阻塞,程序暂时停止运行,直到客户端来访问时才会结束这种阻塞状态。这时该方法会返回一个Socket类型的对象用于表示客户端,通过该对象获取与客户端关联的输出流,并向客户端发送消息。最后调用Socket对象的close()方法将通信关闭。

    建立TCP客户端的思路

      1. 创建Socket类型的对象,并制定服务器的IP地址和端口号
      2. 使用输入输出流进行通信
      3. 关闭相互资源

    接下来编写与客户端的程序。

    public class Client {
        private static final int PORT=8888;        //定义一个端口号
        public static void main(String[] args) throws Exception {
            //创建一个Socket并连接到给出的地址和端口号的计算机
            Socket s = new Socket("192.168.96.1", PORT);
            //得到接收数据的流
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //读取数据
            String r = br.readLine();
            //打印读取到的数据
            System.out.println(r);
            //关闭资源
            br.close();
        }
    }

    在客户端创建Socket对象与服务器端建立连接后,通过Socket对象获得输入流读取服务端发来的数据,并打印结果,结束本次通信。

    多线程的TCP网络程序

    实际上,很多服务器端程序都是允许被多个应用程序访问的。例如门户网站可以被多个用户访问,因此服务器都是多线程的。下面通过一个图例来表示多个用户访问同一个服务器。

     图中代表的是多个客户端访问同一个服务器端,服务器端为每个客户端创建一个对象的Socket,并且开启一个新的线程使两个Socket建立专线进行通信,接下来对TCP通信的服务端进行改进。

    public class Server {
        private static final int PORT=8888;        //定义一个端口号
        public static void main(String[] args) throws Exception{
            //创建ServerSocket对象
            ServerSocket ss = new ServerSocket(PORT);  
            //使用while()循环不停的接收客户端发送的请求
            while(true) {
                //调用accpet()等待客户端的连接
                Socket s = ss.accept();        
                //下面用代码开启一个新线程
                new Thread() {
                    public void run() {
                        try {
                            //获取客户端的输出流
                            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
                            System.out.println("开始与客户端交互数据");    
                            //当客户端接入后,向客户端输出数据
                            bw.write("我是服务器,你好客户端!"); 
                            //模拟置信其他功能占用的时间
                            Thread.sleep(5000);         
                            System.out.println("结束与客户端交互数据");
                            bw.flush();
                            s.close();
                            bw.close();
                        } catch (Exception e) { 
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        }
    }

    使用多线程的方式创建了一个服务器端程序。通过在while循环中调用accept()方法,不停地接收客户端发送的请求,而主线程仍然处于等待状态。

    学习中,博客都是自己学习用的笔记,持续更新改正。。。
  • 相关阅读:
    hdu 1325 判断有向图是否为树
    poj 1182
    Ubuntu 系统 文件操作命令
    vim 快捷键大全
    Git 上传本地命令
    git错误:fatal: Not a git repository (or any of the parent directories): .git
    Git 如何回到过去,然后 再 回到将来
    Git 提供篇
    Linux 的cp命令
    Linux :: vi E212: Can't open file for writing
  • 原文地址:https://www.cnblogs.com/Tunan-Ki/p/11681113.html
Copyright © 2020-2023  润新知