zoukankan      html  css  js  c++  java
  • 网络编程之Socket

    一、网络模型

      1.1什么是网络模型

        网络编程的本质是两个设备之间的数据交换。现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另一个设备的反馈。

      网络模型图:

       

      1.2 IP地址与域名

        IP地址是一个规定,现在使用的是IPv4,既由4个0-255之间的数字组成,在计算机内部存储时只需要4个字节即可。在计算机中,IP地址是分配给网卡的,每个网卡有一个唯一的IP地址,如果一个计算机有多个网卡,则该台计算机则拥有多个不同的IP地址,在同一个网络内部,IP地址不能相同。

        由于IP地址不方便记忆,所以有专门创造了域名(Domain Name)的概念,其实就是给IP取一个字符的名字。

      1.3端口的概念

        使用端口号,可以找到一台设备上唯一的一个程序

      网络编程就是使用IP地址,或域名,和端口连接到另一台计算机上对应的程序,按照规定的协议(数据格式)来交换数据,实际编程中建立连接和发送、接收数据在语言级已经实现,做的更多的工作是设计协议,以及编写生成和解析数据的代码罢了,然后把数据转换成逻辑的结构显示或控制逻辑即可。

    二、Socket

      2.1 什么是socket

        网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

        Socket就是为网络服务提供的一种机制。通讯的两端都有Sokcet,网络通讯其实就是Sokcet间的通讯,数据在两个Sokcet间通过IO传输。

      2.2  TCP与UDP在概念上的区别:

        udp: a、是面向无连接, 将数据及源的封装成数据包中,不需要建立建立连接

                b、每个数据报的大小在限制64k内

          c、因无连接,是不可靠协议

          d、不需要建立连接,速度快

        tcp:a、建议连接,形成传输数据的通道.

                          b、在连接中进行大数据量传输,以字节流方式

                          c、通过三次握手完成连接,是可靠协议

                         d、必须建立连接,效率会稍低

      2.3 UDP协议

      UDP服务器端代码

    class UdpServer {
        public static void main(String[] args) throws IOException {
            System.out.println("udp接受数据启动.......");
            DatagramSocket ds = new DatagraSocket(8080);
            byte[] buf = newbyte[1024];
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            // 阻塞效果,接收到客户端请求才会继续执行
            ds.receive(dp);
            System.out.println("来源:"+dp.getAddress().getHostAddress()+",port:"+dp.getPort());
            String str = new String(dp.getData(),0,dp.getLength());
            System.out.println("客户端发送数据:"+str);
            ds.clos(); 
        }
    }

      UDP客户端代码

    /**
     * @classDesc: 功能描述:(udp客户端)*/
    public class UdpClient {
        public static void main(String[] args) throws IOException {
            System.out.println("udp 发送数据");
            DatagramSocket ds = new DatagramSocket();
            String str = "客户端发送数据....";
            byte[] strByte = str.getBytes();
            DatagramPacket dp = new DatagramPacket(strByte, strByte.length, InetAddress.getByName("192.168.1.3"), 8080);
            ds.send(dp);
            ds.close();
        }
    }

      2.4 TCP协议

      2.4.1 TCP握手协议

      在TCP/IP协议中,TCP协议采用三次握手建立一个连接。 
      第一次握手:建立连接时,客户端发送SYN包(SYN=J)到服务器,并进入SYN_SEND状态,等待服务器确认; 
      第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=J+1),同时自己也发送一个SYN包(SYN=K),即SYN+ACK包,此时服务器V状态; 
      第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=K+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
      完成三次握手,客户端与服务器开始传送数据。

      

      四次分手:

      由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
      (1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
      (2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
      (3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
      (4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。  

      

      1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
        这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在 一个报文里来发送。

        但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报 文和FIN报文多数情况下都是分开发送的.

      2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

        这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

      服务器端代码

    public class TcpServer {
        public static void main(String[] args) throws IOException {
            System.out.println("socket服务器端启动....");
            ServerSocket serverSocket = new ServerSocket(8080);
            //获取客户端对象
            Socket accept = serverSocket.accept();
            InputStream inputStream = accept.getInputStream();
            byte[] buf= newbyte[1024];
            intlen=inputStream.read(buf);
            String str =new String(buf,0,len);
            System.out.println("str:"+str);
            serverSocket.close();
        }
    }

      客户端代码

            System.out.println("socket启动....");
            Socket socket = new Socket("192.168.1.3", 8080);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("我是客戶端....".getBytes());
            socket.close();
  • 相关阅读:
    Python 爬虫js加密破解(一) 爬取今日头条as cp 算法 解密
    Python 爬虫实例(2)—— 爬取今日头条
    Python 爬虫实例(1)—— 爬取百度图片
    python 操作redis之——HyperLogLog (八)
    python 操作redis之——有序集合(sorted set) (七)
    Python操作redis系列之 列表(list) (五)
    Python操作redis系列以 哈希(Hash)命令详解(四)
    Python操作redis字符串(String)详解 (三)
    How to Install MySQL on CentOS 7
    Linux SSH远程文件/目录 传输
  • 原文地址:https://www.cnblogs.com/woniusky/p/10688512.html
Copyright © 2011-2022 走看看