[Java] 网络编程

网络连接

  • 目的:实现不同主机间数据的共享,早期是主动共享,现在是被动共享
  • OSI七层模型,TCP五层模型,所有数据在每一层上进行信息处理,最终通过物理设备(网卡)发送,网卡在整个网络中有唯一的Mac地址
  • 网络编程:正对于TCP/UDP两种协议进行的网络开发,两个协议的细节组成非常繁琐,对网络协议的抽象性管理逻辑称为Socket编程
  • Socket内部两种模式
    • C/S(Client/Server):需要开发两套程序,一套服务器程序,一套客户端程序,在进行维护的时候服务器端和客户端的程序都需要更新(如QQ),使用特定的数据传输协议(用户自定义)及一些非公开端口,安全性较高
    • B/S(Browser/Server):基于浏览器实现客户端应用,只需要开发服务器端的程序,如需进行维护只需修改服务器代码,维护与开发成本降低,使用公共的HTTP协议(基于TCP协议的实现),所以安全性较差
  • 网络编程属于C/S模型,Web开发属于B/S模型
  • C/S模型分为
    • TCP程序:三次握手,四次挥手
    • UDP程序:发送数据报,接收数据报的一方不一定可以接收到数据(发短信,手机关机)

 

 

 

 

 

网络程序

  •  java.net包完成,提供两个类
    • java.net.ServerSocket:工作在服务器端的程序类,定义服务器监听端口,及接收客户端请求
    • java.net.Socket:每一个客户端都使用一个Socket的概念进行描述
  • 端口是进入服务的“门”,每个端口只能绑定一个服务,建议用5000以上
  • 连接的目的是进行IO通讯

 

服务器端程序

  • 验证服务器是否可正常使用,可利用操作系统中的telnet命令
  • 传输字节数据,用PrintStream
  • win+R > Telnet > open localhost 9999
  • telnet 仅是基础测试环境,不是客户端
  • 服务器端数据的输出,就是客户端数据的输入
  • accept():打开服务器监听
 1 import java.io.PrintStream;
 2 import java.net.ServerSocket;
 3 import java.net.Socket;
 4 
 5 public class HelloServer {
 6     public static void main(String[] args) throws Exception{
 7         ServerSocket serversocket = new ServerSocket(9999); // 本程序在9999端口连接
 8         System.out.println("[HelloServer] 服务器端启动监听... ...");
 9         // 每一个连接到服务器端的客户端都通过Socket对象来描述,所以要等待连接
10         Socket client = serversocket.accept(); // 等待客户端连接
11         // 向指定的Socket实现数据的输出,获取Socket的输出流
12         PrintStream out = new PrintStream(client.getOutputStream()); // 通过打印流输出
13         out.println("www.yootk.com"); // 输出信息
14         client.shutdownOutput(); // 数据发送完毕后再关闭
15         serversocket.close(); // 关闭整个服务器
16     }
17 }
View Code

客户端程序

  • Socket类描述的就属于客户端信息,在客户端主要用它来实现服务器端的连接,而服务器端每个连接到服务器的客户都通过Socket来描述
 1 import java.net.Socket;
 2 import java.util.Scanner;
 3 
 4 public class HelloClient {
 5     public static void main(String[] args) throws Exception{
 6         // Socket是工作在客户端的程序类,每一个Socket对象描述的都是一个独立的客户端
 7         Socket client = new Socket("localhost",9999);
 8         Scanner scanner = new Scanner(client.getInputStream()); // 服务器端的输出为客户端的输入
 9         if(scanner.hasNext()) { // 此时有数据需要进行输出
10             System.out.println("[HelloClient] "+scanner.next());
11         }
12         client.shutdownInput();
13     }
14 }
View Code

 

Echo模型

  • 网络通讯程序的核心接口
  • 客户端发送数据给服务器端,服务器端接收到数据后直接进行回应
  • 回应处理可持续进行,当客户端确认不再继续交互时断开
  • Socket可获取InputStream、OutputStream
  • 实现最为核心的网络接口交互模型,再继续扩展可实现更加丰富内容的传输

服务器端程序

 1 import java.io.PrintStream;
 2 import java.net.ServerSocket;
 3 import java.net.Socket;
 4 import java.util.Scanner;
 5 
 6 public class EchoServer {
 7     public static void main(String[] args) throws Exception{
 8         ServerSocket serversocket = new ServerSocket(9999);
 9         Socket client = serversocket.accept(); // 进入阻塞状态,等待客户端连接
10         Scanner scanner = new Scanner(client.getInputStream()); // 服务器端输入流
11         PrintStream out = new PrintStream(client.getOutputStream()); // 服务器端输出流
12         boolean flag = true; 
13         while(flag) {
14             if(scanner.hasNext()) { // 如果现在有输入的数据内容
15                 String value = scanner.next().trim();
16                 if(value.equalsIgnoreCase("exit")) {
17                     out.println("[EchoServer]exit");
18                     flag = false;
19                     break;
20                 }
21                 out.println("ECHO:"+ value);
22             }
23         }
24         serversocket.close();
25     }
26 }
View Code

客户端程序

 1 import java.io.PrintStream;
 2 import java.net.Socket;
 3 import java.util.Scanner;
 4 
 5 public class EchoClient {
 6     public static void main(String[] args) throws Exception{
 7         Socket client = new Socket("localhost",9999);
 8         Scanner scanner = new Scanner(client.getInputStream()); // 客户端输入流
 9         PrintStream out = new PrintStream(client.getOutputStream()); // 客户端输出流
10         boolean flag = true;
11         while(flag) {
12             String value = KeyboardInput.getString("请输入数据:");
13             out.println(value);
14             if(scanner.hasNext()) {
15                 System.out.println("[ECHO客户端]" + scanner.next()); //服务器端响应
16             }
17             if(value.equalsIgnoreCase("exit")){
18                 flag = false;
19             }
20         }
21         client.close();
22     }
23 }
View Code

 

BIO处理模型

  • BIO(Blocking IO、阻塞IO处理)是最为传统的一种网络通讯模型的统一描述,解决服务器的并发处理问题,ECHO模型属于单线程服务器的开发,即同一个时间段只能有一个线程进行访问
  • 创建新的线程处理类,包裹Socket对象
  • 问题:需要先连接,然后服务器分配线程对象,若此时客户端即使没有与服务器端产生任何交互,那么这个线程的连接也要维持着,面对高并发访问程序会导致性能浪费,为解决次问题创建了NIO模型

 

服务器端

 1 import java.net.ServerSocket;
 2 import java.net.Socket;
 3 
 4 public class EchoServer {
 5     public static void main(String[] args) throws Exception{
 6         ServerSocket serversocket = new ServerSocket(9999);
 7         boolean flag = true; 
 8         while(flag) {
 9             Socket client = serversocket.accept();
10             new Thread(new EchoHandle(client)).start();
11         }
12         serversocket.close();
13     }
14 }
View Code

服务器端线程类

 1 import java.io.PrintStream;
 2 import java.net.Socket;
 3 import java.util.Scanner;
 4 
 5 public class EchoHandle implements Runnable{
 6     private Socket client;
 7     public EchoHandle(Socket client) {
 8         this.client = client;
 9     }
10     @Override
11     public void run() {
12         try {        
13             Scanner scanner = new Scanner(client.getInputStream()); // 服务器端输入流
14             PrintStream out = new PrintStream(client.getOutputStream()); // 服务器端输出流
15             boolean flag = true; 
16             while(flag) {
17                 if(scanner.hasNext()) { // 如果现在有输入的数据内容
18                     String value = scanner.next().trim();
19                     if(value.equalsIgnoreCase("exit")) {
20                         out.println("[EchoServer]exit");
21                         flag = false;
22                     }else {
23                         out.println("ECHO:"+ value);
24                     }
25                 }
26             }
27             scanner.close();
28             out.close();
29             client.close();
30         }catch(Exception e) {}
31     }
32 }
View Code

客户端

 1 import java.io.PrintStream;
 2 import java.net.Socket;
 3 import java.util.Scanner;
 4 
 5 public class EchoClient {
 6     public static void main(String[] args) throws Exception{
 7         Socket client = new Socket("localhost",9999);
 8         Scanner scanner = new Scanner(client.getInputStream()); // 客户端输入流
 9         PrintStream out = new PrintStream(client.getOutputStream()); // 客户端输出流
10         boolean flag = true;
11         while(flag) {
12             String value = KeyboardInput.getString("请输入数据:");
13             out.println(value);
14             if(scanner.hasNext()) {
15                 System.out.println("[ECHO客户端]" + scanner.next()); //服务器端响应
16             }
17             if(value.equalsIgnoreCase("exit")){
18                 flag = false;
19             }
20         }
21         scanner.close();
22         out.close();
23         client.close();
24     }
25 }
View Code

 

UDP程序

  • TCP:可靠连接模式,可保证接收稳定性,但会带来严重的性能损耗
  • UDP:不保证用户一定可以收到,但性能较高
  • 类比:发传单
  • 实例:手机短信(不开机收不到)
  • UDP客户端:等待服务器端进行消息数据的发送,如接收到内容则继续向下执行,进行具体内容输出
  • HTTP协议里可能将TCP协议更换
  • 用Netty开发更加简单

服务器端

 1 import java.net.DatagramPacket;
 2 import java.net.DatagramSocket;
 3 import java.net.InetAddress;
 4 
 5 public class UDPServer {
 6     public static void main(String[] args) throws Exception{
 7         DatagramSocket server = new DatagramSocket(8000); // 服务器端端口
 8         String message = "www.yootk.com";
 9         DatagramPacket packet = new DatagramPacket(message.getBytes(),0,message.length(),InetAddress.getByName("localhost"),9999);
10         server.send(packet); // 发送数据报
11         System.out.println("[UDPServer]finished...");
12         server.close();
13     }
14 }
View Code

客户端

 1 import java.net.DatagramPacket;
 2 import java.net.DatagramSocket;
 3 
 4 public class UDPClient {
 5     public static void main(String[] args) throws Exception{
 6         DatagramSocket client = new DatagramSocket(9999);
 7         byte data[] = new byte[1024];
 8         DatagramPacket packet = new DatagramPacket(data, data.length);
 9         System.out.println("[UDPClient]wait...");
10         client.receive(packet);
11         System.out.println("[UDPClient]"+ new String(data,0,packet.getLength()));
12     }
13 }
View Code

 

posted @ 2020-03-11 13:05  cxc1357  阅读(112)  评论(0编辑  收藏  举报