TCP与UDP网络编程

avatar
作者
筋斗云
阅读量:5

网络通信协议

在这里插入图片描述

java.net 包中提供了两种常见的网络协议的支持:

  • UDP:用户数据报协议(User Datagram Protocol)
  • TCP:传输控制协议(Transmission Control Protocol)

TCP协议与UDP协议

TCP协议

  • TCP协议进行通信的两个应用进程:客户端、服务端
  • 使用TCP协议前,须先建立TCP连接,形成基于字节流的传输数据通道
  • 传输前,采用“三次握手”方式,点对点通信,是可靠
    • TCP协议使用重发机制,当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体确认信息,如果没有收到另一个通信实体确认信息,则会再次重复刚才发送的消息
  • 在连接中可进行大数据量的传输
    传输完毕,需释放已建立的连接,效率低

UDP协议

  • UDP协议进行通信的两个应用进程:发送端、接收端
  • 将数据、源、目的封装成数据包(传输的基本单位),不需要建立连接
  • 发送不管对方是否准备好,接收方收到也不确认,不能保证数据的完整性,故是不可靠
  • 每个数据报的大小限制在64K
  • 发送数据结束时无需释放资源,开销小,通信效率高
  • 适用场景:音频、视频和普通数据的传输。例如视频会议

生活案例

TCP生活案例:打电话

UDP生活案例:发送短信、发电报

TCP协议

三次握手

在这里插入图片描述

四次挥手

在这里插入图片描述

网络编程API

Socket类

基本介绍

在这里插入图片描述

在这里插入图片描述

示意图:

在这里插入图片描述

理解客户端、服务端

  • 客户端:

    • 自定义
    • 浏览器(browser — server)
  • 服务端:

    • 自定义
    • Tomcat服务器

TCP网络编程

通信模型

在这里插入图片描述

例题1

客户端发送内容给服务端,服务端将内容打印到控制台上。

public class TCPTest1 {      //客户端     @Test     public void client() {         Socket socket = null;         OutputStream os = null;          try {             // 1.创建一个Socket             InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); //声明ip地址             int port = 8989; //声明端口号             socket = new Socket(inetAddress,port);              // 2.发送数据             os = socket.getOutputStream();             os.write("你好,我是客户端,请多多关照".getBytes());         } catch (IOException e) {             e.printStackTrace();         } finally {             // 3.关闭socket、流             try {                 if (socket != null)                     socket.close();             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (os != null)                     os.close();             } catch (IOException e) {                 e.printStackTrace();             }         }     }      //服务端     @Test     public void server() {         ServerSocket serverSocket = null;         Socket socket = null; //阻塞式方法         InputStream is = null;         try {             // 1.创建一个ServerSocket             int port = 8989;             serverSocket = new ServerSocket(port);              // 2.调用accept(),接收客户端的Socket             socket = serverSocket.accept();             System.out.println("服务器端已开启");              System.out.println("收到了来自于" + socket.getInetAddress().getHostAddress() + "的连接");              // 3.接收数据             is = socket.getInputStream();             byte[] buffer = new byte[1024];             ByteArrayOutputStream baos = new ByteArrayOutputStream(); //内部维护了一个byte[]             int len;             while ((len = is.read(buffer)) != -1) {                 // 错误的,可能会出现乱码 //                String str = new String(buffer,0,len); //                System.out.println(str);                  //正确的                 baos.write(buffer,0,len);             }              System.out.println(baos.toString());              System.out.println("\n数据接收完毕");         } catch (IOException e) {             e.printStackTrace();         } finally {             // 4.关朗Socket、ServerSocket、流             try {                 if (socket != null) {                     socket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (serverSocket != null) {                     serverSocket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (is != null) {                     is.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }         }     } } 

例题2

客户端发送文件给服务端,服务端将文件保存在本地。

public class TCPTest2 {     //客户端     @Test     public void client() {         // 1.创建Socket         // 指明对方(即为服务器)的ip地址和端口号         Socket socket = null;         FileInputStream fis = null;         OutputStream os = null;         try {             InetAddress inetAddress = InetAddress.getByName("127.0.0.1");             int port = 9090;             socket = new Socket(inetAddress,port);              // 2.创建File的实例、FileInputstream的实例             File file = new File("huan.jpg");             fis = new FileInputStream(file);              // 3.通过Socket,获取输出流             os = socket.getOutputStream();              // 读写数据             byte[] buffer = new byte[1024];             int len;             while ((len = fis.read(buffer)) != -1) {                 os.write(buffer,0,len);             }             System.out.println("数据发送完毕");          } catch (IOException e) {             e.printStackTrace();         } finally {             // 4.关闭Socket和相关的流             try {                 if (os != null) {                     os.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (fis != null) {                     fis.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (socket != null) {                     socket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }         }     }      //服务端     @Test     public void server() {         ServerSocket serverSocket = null;         Socket socket = null;         InputStream is = null;         FileOutputStream fos = null;         try {             // 1.创建ServerSocket             int port = 9090;             serverSocket = new ServerSocket(port);              // 2.接收来自于客户端的socket:accept()             socket = serverSocket.accept();              // 3.通过Socket获取一个输入流             is = socket.getInputStream();              // 4.创建File类的实例、File0utputstream的实例             File file = new File("huan_copy.jpg");             fos = new FileOutputStream(file);              // 5.读写过程             byte[] buffer = new byte[1024];             int len;             while ((len = is.read(buffer)) != -1) {                 fos.write(buffer,0,len);             }              System.out.println("数据接收完毕");         } catch (IOException e) {             e.printStackTrace();         } finally {             // 6.关闭相关的Socket和流             try {                 if (fos != null) {                     fos.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (is != null) {                     is.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (socket != null) {                     socket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (serverSocket != null) {                     serverSocket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (is != null) {                     is.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }         }     } } 

例题3

从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功"给客户端。并关闭相应的连接。

public class TCPTest3 {     //客户端     @Test     public void client() {         // 1.创建Socket         // 指明对方(即为服务器)的ip地址和端口号         Socket socket = null;         FileInputStream fis = null;         OutputStream os = null;         ByteArrayOutputStream baos = null;         InputStream is = null;         try {             InetAddress inetAddress = InetAddress.getByName("127.0.0.1");             int port = 9090;             socket = new Socket(inetAddress, port);              // 2.创建File的实例、FileInputstream的实例             File file = new File("huan.jpg");             fis = new FileInputStream(file);              // 3.通过Socket,获取输出流             os = socket.getOutputStream();              // 4.读写数据             byte[] buffer = new byte[1024];             int len;             while ((len = fis.read(buffer)) != -1) {                 os.write(buffer, 0, len);             }             System.out.println("数据发送完毕");              // 5.客户端表明不再继续发送数据             socket.shutdownOutput();              // 6.接收来自于服务器端的数据             is = socket.getInputStream();             baos = new ByteArrayOutputStream();             byte[] buffer1 = new byte[5];             int len1;             while ((len1 = is.read(buffer1)) != -1) {                 baos.write(buffer1, 0, len1);             }             System.out.println(baos.toString());          } catch (IOException e) {             e.printStackTrace();         } finally {             // 7.关闭Socket和相关的流             try {                 baos.close();             } catch (Exception e) {                 e.printStackTrace();             }             try {                 is.close();             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (os != null) {                     os.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (fis != null) {                     fis.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (socket != null) {                     socket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }         }     }      //服务端     @Test     public void server() {         ServerSocket serverSocket = null;         Socket socket = null;         InputStream is = null;         FileOutputStream fos = null;         OutputStream os = null;         try {             // 1.创建ServerSocket             int port = 9090;             serverSocket = new ServerSocket(port);              // 2.接收来自于客户端的socket:accept()             socket = serverSocket.accept();              // 3.通过Socket获取一个输入流             is = socket.getInputStream();              // 4.创建File类的实例、File0utputstream的实例             File file = new File("huan_copy2.jpg");             fos = new FileOutputStream(file);              // 5.读写过程             byte[] buffer = new byte[1024];             int len;             while ((len = is.read(buffer)) != -1) {                 fos.write(buffer, 0, len);             }              // 6.服务端发送数据给客户端             os = socket.getOutputStream();             os.write("你的图片很漂亮,我接收到了".getBytes());              System.out.println("数据接收完毕");         } catch (IOException e) {             e.printStackTrace();         } finally {             // 7.关闭相关的Socket和流             try {                 os.close();             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (fos != null) {                     fos.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (is != null) {                     is.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (socket != null) {                     socket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (serverSocket != null) {                     serverSocket.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }             try {                 if (is != null) {                     is.close();                 }             } catch (IOException e) {                 e.printStackTrace();             }         }     } } 

【案例】聊天室

聊天室模型

在这里插入图片描述

服务器端

public class ChatSeverTest {     //这个集合用来存储所有在线的客户端     static ArrayList<Socket> online = new ArrayList<Socket>();      public static void main(String[] args) throws IOException {         //1、启动服务器,绑定端口号         ServerSocket server = new ServerSocket(8989);          //2、接收n多的客户端同时连接         while (true) {             Socket accept = server.accept();              online.add(accept);//把新连接的客户端添加到online列表中              MessageHandler mh = new MessageHandler(accept);             mh.start();         }     }      static class MessageHandler extends Thread {         private Socket socket;         private String ip;          public MessageHandler(Socket socket) {             super();             this.socket = socket;         }          @Override         public void run() {             try {                 ip = socket.getInetAddress().getHostAddress();                 //插入:给其他客户端转发“我上线了”                 sendToOther(ip+"上线了");                  //(1)接收该客户端的发送的消息                 InputStream input = socket.getInputStream();                 InputStreamReader reader = new InputStreamReader(input);                 BufferedReader br = new BufferedReader(reader);                  String str;                  while ((str = br.readLine()) != null) {                     //(2)给其他在线客户端转发                     sendToOther(ip + ":" + str);                 }                  sendToOther(ip + "下线了");             } catch (IOException e) {                 try {                     sendToOther(ip + "掉线了");                 } catch (Exception e1) {                     e1.printStackTrace();                 }             } finally {                 //从在线人员中移除我                 online.remove(socket);             }          }          //封装一个方法:给其他客户端转发xxx消息         public void sendToOther(String message) throws IOException {             //遍历所有的在线客户端,一一转发             for (Socket on : online) {                 OutputStream every = on.getOutputStream();                 PrintStream ps = new PrintStream(every);                  ps.println(message);             }         }     } } 

客户端

public class ChatClientTest {     public static void main(String[] args) throws Exception {         //1、连接服务器         Socket socket = new Socket("127.0.0.1", 8989);          //2、开启两个线程         //(1)一个线程负责看别人聊,即接收服务器转发的消息         Receive receive = new Receive(socket);         receive.start();          //(2)一个线程负责发送自己的话         Send send = new Send(socket);         send.start();          send.join();//等我发送线程结束了,才结束整个程序          socket.close();     } }  class Send extends Thread{     private Socket socket;     public Send(Socket socket) {         super();         this.socket = socket;     }      @Override     public void run() {         try {             OutputStream outputStream = socket.getOutputStream();             //按行打印             PrintStream ps = new PrintStream(outputStream);             Scanner input = new Scanner(System.in);              //从键盘不断的输入自己的话,给服务器发送,由服务器给其他人转发             while (true) {                 System.out.println("自己的话:");                 String str = input.nextLine();                 if ("bye".equals(str)) {                     break;                 }                 ps.println(str);             }              input.close();         } catch (IOException e) {             e.printStackTrace();         }     } }  class Receive extends Thread{     private Socket socket;     public Receive(Socket socket) {          super();          this.socket = socket;     }      @Override     public void run() {         try {             InputStream inputStream = socket.getInputStream();             Scanner input = new Scanner(inputStream);              while (input.hasNextLine()) {                 String line = input.nextLine();                 System.out.println(line);             }         } catch (IOException e) {             e.printStackTrace();         }     } } 

UDP网络编程

通信模型

在这里插入图片描述

示例

public class UDPTest {          //发送端     @Test     public void sender() throws Exception {         //1.创建DatagramSocket的实例         DatagramSocket ds = new DatagramSocket();          //2、将数据、目的地的ip,目的地的端口号部封装在DatagramPacket数据报中         InetAddress inetAddress = InetAddress.getByName("127.0.0.1");         int port = 9090;         byte[] bytes = "我是发送端".getBytes("utf-8");         DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, inetAddress, port);          //发送数据         ds.send(packet);         ds.close();     }      //接收端     @Test     public void receiver() throws IOException {         //1.创建DatagramSocket的实例         int port = 9090;         DatagramSocket ds = new DatagramSocket(port);          //2. 创建数据报的对象,用于接收发送端发送过来的数据         byte[] buffer = new byte[1024 * 64];         DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);          //3.接收数据         ds.receive(packet);          //4.获取数据,并打印到控制台上         String str = new String(packet.getData(), 0, packet.getLength());         System.out.println(str);          ds.close();     } } 

URL编程

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!