网络编程(Tcp/Udp实现聊天、文件上传)

网络编程

1.1 概述

计算机网络是指将位置不同的多台[计算机 通过通信线路连接起来,实现资源共享和信息传递的计算机系统

1.2 网络通信的要素

  • ip和端口
  • 网络通信协议(tcp/udp)

1.3 Ip地址(Internet Protocol)

  • 定位唯一一台计算机

  • 127.0.0.0:本机 localhost

  • ip地址的分类(ip4/ip6)

    • ip4 四个字节组成 2011年用尽

    • Ip6 通常写成8组,每组为四个十六进制数的形式 非常多,基本用不完

      CDCD:910A:2222:5498:8475:1111:3900:2020
      1030::C9B4:FF12:48AA:1A2B
      2000:0:0:0:0:0:0:1
      
    • 公网(互联网)/私网(局域网)

      • 192.168.xx.xx 这种类型的代表的就是私网
      • 其它类型 a.b.c.d 代表公网
    • 域名:ip不方便记忆 不能显示地址组织的名称和性质,人们设计出了域名,通过DNS将域名和Ip关联,方便访问

1.4 端口(port)

端口:计算机与外界通讯交流的出口

  • 代表计算机上的某一个程序的进程
  • 不同的进程有不同的端口,代表不同的程序
  • 被规定0-65535中间
  • TCP UDP,单个协议下,端口互不冲突
  • 端口分类
    • 公有端口 从0到1023
      • http:8080
      • ftp:21
      • https:443
    • 程序注册端口1024~49151,分配给用户或程序
      • tomcat:8080
      • Mysql:3306
      • Oracle:1521
    • 动态和/或私有端口 49152~65535

1.5 通信协议

通信协议:双方必须遵循的规则和约定。 确保网络中数据顺利地传送到确定的地方。

常见协议:

  • tcp/ip协议:传输控制协议/Internet协议,TCP/IP是由一组具有专业用途的多个子协议组合而成的,这些子协议包括TCP、IP、UDP、ARP、ICMP等

  • tcp协议:打电话

    • 一种面向连接的、可靠的、基于字节流的传输层通信协议

    • 连接稳定(一定会发送成功)

      • 连接 三次握手
      • 断开 四次挥手
    • 分客户端、服务端

    • 传输完成,断开连接,效率低

    • 接收消息代码

          public static void main(String[] args) {
              try {
                  //等待 接收消息
                  ServerSocket serverSocket = new ServerSocket(1025);
                  //等待服务连接
                  Socket socket = serverSocket.accept();
                  InputStream inputStream = socket.getInputStream();
                  Scanner scanner = new Scanner(inputStream);
                  while (scanner.hasNext()){
                      System.out.print(scanner.next());
                  }
                  inputStream.close();
                  socket.close();
                  serverSocket.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
    • 发送消息必须是服务端开启才能发送,否则

    java.net.ConnectException: Connection refused: connect
    	at java.net.DualStackPlainSocketImpl.connect0(Native Method)
    	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
    	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    	at java.net.Socket.connect(Socket.java:589)
    	at java.net.Socket.connect(Socket.java:538)
    	at java.net.Socket.<init>(Socket.java:434)
    	at java.net.Socket.<init>(Socket.java:244)
    	at tcpDemo.TcpClientDemo1.main(TcpClientDemo1.java:12)
    
    Process finished with exit code 0
    
    
    • 发送消息代码
        public static void main(String[] args) {
            try {
                //发送消息
                InetAddress inetAddress = InetAddress.getByName("localhost");
                Socket socket = new Socket(inetAddress, 1025);
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("helloTcp".getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    • 使用FTP实现文件上传

      • 服务器代码(开启服务 等待上传)
      public static void main(String[] args) throws Exception {
              //创建服务
              ServerSocket serverSocket = new ServerSocket(1026);
              //监听客户端连接
              Socket socket = serverSocket.accept();
              //获取输入流
              InputStream is = socket.getInputStream();
              //输出文件
              FileOutputStream fos = new FileOutputStream(new File("2.jpg"));
              byte[] buffer = new byte[1024];
              int len ;
              while ((len=is.read(buffer))!=-1){
                  fos.write(buffer,0,len);
              }
      
              //告诉客户端接收到了文件
              OutputStream os = socket.getOutputStream();
              os.write("服务端收到了文件".getBytes());
      
              //关闭资源
              os.close();
              fos.close();
              is.close();
              socket.close();
              serverSocket.close();
      
          }
      

      -客户端代码(上传文件,服务开启时才能上传成功)

        public static void main(String[] args) throws Exception {
                //创建连接
                Socket socket = new Socket("localhost",1026);
                //获取输出流
                OutputStream outputStream = socket.getOutputStream();
                //读取文件
                FileInputStream fis=new FileInputStream(new File("1.jpg"));
        
                byte[] buffer =new byte[1024];
                int len;
                while ((len=fis.read(buffer))!=-1){
                    outputStream.write(buffer,0,len);
                }
        
        
                //通知服务器 已经传输完毕
                socket.shutdownOutput();
        
                //文件发送完毕,接收服务端返回消息
                InputStream is = socket.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer2 = new byte[1024] ;
                int len2;
                while ((len2=is.read(buffer2))!=-1){
                    baos.write(buffer2,0,len2);
                }
                System.out.println("客户端:   "+baos.toString());
        
                //关闭资源
                fis.close();
                outputStream.close();
                socket.close();
        
        
            }
      
  • UDP协议:发短信

    • 不连接 不稳定(消息可能发送失败)

    • 客户端 服务端 不明确

    • UDP实现消息发送

      • 发送方代码(无论是否有人接收,都能发送成功)
      public static void main(String[] args) throws Exception{
              DatagramSocket socket = new DatagramSocket(2222);
              while (true){
                  BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                  String readLine = reader.readLine();
                  DatagramPacket packet = new DatagramPacket(readLine.getBytes(),0,readLine.getBytes().length,new InetSocketAddress("localhost",2233));
                  socket.send(packet);
                  if(readLine.equals("bye")){
                      break;
                  }
              }
              socket.close();
          }
      
      • 接收方代码
      public static void main(String[] args) throws  Exception{
              DatagramSocket socket = new DatagramSocket(2233);
              while (true){
                  byte[] buffer = new byte[1024];
                  DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
                  socket.receive(datagramPacket);
      
                  byte[] data = datagramPacket.getData();
                  String receiveStr = new String(data,0,data.length).trim();
                  System.out.println(receiveStr);
                  if(receiveStr.equals("bye")){
                      break;
                  }
              }
              socket.close();
          }
      
    • 实现聊天

      • 接收方
      package udpDemo;
      
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.SocketException;
      
      public class TaskReveive implements Runnable{
          private int reveivePort;
          private DatagramSocket socket;
          public TaskReveive(int reveivePort) {
              this.reveivePort = reveivePort;
              try {
                  socket = new DatagramSocket(reveivePort);
              } catch (SocketException e) {
                  e.printStackTrace();
              }
          }
      
          @Override
          public void run() {
              while (true){
                  try {
                      byte[] buffer = new byte[1024];
                      DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
                      socket.receive(datagramPacket);
                      byte[] data = datagramPacket.getData();
                      String receiveStr = new String(data,0,data.length).trim();
                      System.out.println(receiveStr);
                      if(receiveStr.equals("bye")){
                          break;
                      }
                  }catch (Exception e){
                      e.printStackTrace();
                  }
              }
              socket.close();
          }
      }
      
      
      • 发送方
      package udpDemo;
      
      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetSocketAddress;
      
      public class TaskSender implements Runnable{
          private int sendPort;
          private String sendIp;
          private int myPort;
          private String myIP;
      
          public TaskSender(int sendPort, String sendIp, int myPort, String myIP) {
              this.sendPort = sendPort;
              this.sendIp = sendIp;
              this.myPort = myPort;
              this.myIP = myIP;
          }
      
          @Override
          public void run(){
              try {
                  DatagramSocket socket = new DatagramSocket(myPort);
                  while (true){
                      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                      String readLine = reader.readLine();
                      InetSocketAddress inetSocketAddress = new InetSocketAddress(sendIp, sendPort);
                      DatagramPacket packet = new DatagramPacket(readLine.getBytes(),0,readLine.getBytes().length,inetSocketAddress);
                      socket.send(packet);
                      if(readLine.equals("bye")){
                          break;
                      }
                  }
                  socket.close();
              }catch (Exception e){
                  e.printStackTrace();
              }
      
          }
      }
      
      
      • 每人一个接收消息 一个发送消息 实现通信
      package udpDemo;
      
      public class TaskStudent {
          public static void main(String[] args) {
              new Thread(new TaskSender(2233, "localhost", 2244, "localhost")).start();
              new Thread(new TaskReveive(3322)).start();
          }
      }
      
      package udpDemo;
      
      public class TestTeacher {
          public static void main(String[] args) {
              new Thread(new TaskSender(3322, "localhost", 3323,"localhost")).start();
              new Thread(new TaskReveive(2233)).start();
          }
      }
      
      

1.6 面试题

  1. 说一下HTTP协议

    HTTP协议:超文本传输协议,属于应用层协议,规定了客户端与服务端传输数据的格式;它是无状态的,对于前面传送过的信息没有记录;请求方式有GET,POST,HEAD,PUT,DELETE等等。

    最主要的get,post方法;

    • get请求:数据会以URL的形式传输,对数据大小有一定的限制,安全性比较低 ,用于传输一些比较小,安全性要求低的数据;

    • post请求:数据是通过数据包的形式传输,比较安全,用于传输比较大的,对于安全性要求较高的数据;

      HTTP转态码: 状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

      1xx:指示信息--表示请求已接收,继续处理
      2xx:成功--表示请求已被成功接收、理解、接受
      	200 OK                        //客户端请求成功
      3xx:重定向--要完成请求必须进行更进一步的操作
      4xx:客户端错误--请求有语法错误或请求无法实现
      	400 Bad Request               //客户端请求有语法错误,不能被服务器所理解
        401 Unauthorized              //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 
        403 Forbidden                 //服务器收到请求,但是拒绝提供服务
        404 Not Found                 //请求资源不存在,eg:输入了错误的URL
      5xx:服务器端错误--服务器未能实现合法的请求
      	 500 Internal Server Error     //服务器发生不可预期的错误
     	 503 Server Unavailable        //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
    
  2. Tcp/Udp的区别

    • 基于连接与无连接
    • TCP要求系统资源较多,UDP较少; (原因是tcp需要保持连接,udp不需要)
    • UDP程序结构较简单
    • 流模式(TCP)与数据报模式(UDP);
    • TCP保证数据正确性,UDP可能丢包 (原因是tcp连接时发送 ,udp无连接,接收方无连接时可能会丢包)
    • TCP保证数据顺序,UDP不保证
    1. tcp建立连接和断开连接
  • 建立连接(三次握手) 双方都确认准备完毕开始发送

    • 主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”这是第一次对话
    • 主机B向主机A发送同意连接和要求同步:可以,你什么时候发?”
    • 主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”

    三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。
    img

  • 断开连接(四次挥手)

    • 关闭方(可以是客户端也可以是服务端)发送一个包,表示自己没有要发送的数据了,这个时候开始等待被关闭方返回的消息
  • 被关闭方接收到了关闭方发送的报文以后,也会发送数据包,告诉关闭方,他收到了关闭方发送的关闭连接的请求,但是这个时候,服务端可能还有没有发送的数据,这个时候可以发送数据。

    • 被关闭方告诉关闭方,它数据发送完成,它也要关闭了
  • 关闭方,告诉被关闭方,它知道了。

img

  • 为什么要4次挥手?

    • 确保数据能够完整传输。

    • 当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。

    • 但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后,

    • 再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值