网络编程

---恢复内容开始---

  网络:将地理上分开的主机连接在一起就形成了网络。但是在java中的网络编程不是已物理主机区分的。而是以不同的JVM进程来区分的

  虽然JVM帮助用户隐藏了一些网络原始信息,但是有一些的操作还是留给了用户来实现了,例如:网络的连接分为两种:TCP(可靠的数据连接),UDP(不可靠的数据连接)。

  从网络编程的本质来讲也分为两种类型:

    C/S结构(客户/服务器):需要开发两套程序,一套是服务器端程序,另外一套是客户端程序。如果要更新,两套都要修改,开发复复杂度高,但是安全,稳定,因为可以自定义协议,自定义传输端口;

    B/S结构(浏览器/服务器):通过浏览器来访问服务器端程序,开发者只需要开发服务器端代码即可,只需要维护一套程序,由于使用的是公共的协议,公开的端口,所以安全性较差。

开发一个基本的C/S程序

  下面编写一个服务器端代码和一个客户端代码,主要是通过客户端去连接服务器端取得一些信息,服务器端只输出一次“HelloWorld”就表示操作结束。

  如果要开发网络程序,使用java.net程序包即可,这个包里面有两个类:ServerSocket(服务器) Socket(客户端)。

范例:编写一个服务器端程序

 1 package cn.Tony.netdemo.hello.server;
 2 
 3 import java.io.PrintWriter;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 
 7 public class HelloServer {
 8     public static void main(String[] args) throws Exception {
 9         //1.创建一个服务器端的对象,所有的服务器一定要有一个监听端口
10         ServerSocket server=new ServerSocket(9999);//此时的服务在9999端口上等待连接
11         System.out.println("等客户来连接......");
12         //2.需要等待客户连接,也就是说此时的程序在此处会进入到一个阻塞状态
13         Socket client=server.accept();//表示等待连接,连接的是客户
14         PrintWriter out=new PrintWriter(client.getOutputStream());
15         out.println("Hello World!");//要有换行
16         out.close();
17         server.close();
18     }
19 }

范例:编写客户端

package cn.Tony.netdemo.hello.client;

import java.net.Socket;
import java.util.Scanner;

public class HelloClient {

    public static void main(String[] args) throws Exception{
        //1.表示连接到指定的服务器端的主机名称和端口。localhost=127.0.0.1
        Socket client=new Socket("localhost",9999);
        //2.等待进行服务器端的输出,服务器端输出对客户端是输入4
        Scanner scan=new Scanner(client.getInputStream());
        scan.useDelimiter("\n");
        if(scan.hasNext()) {
            System.out.println(scan.next());
        }
        client.close();
    }
}

  这个时候的服务器只能处理一次请求操作

ECHO程序

  网络编程有一个最为经典的程序案例:ECHO程序的核心本质在于:将用户接受到的数据前面追加一个“ECHO”的头信息进行返回。这个程序要求用户可以一直进行信息的输入,一直到用户byebye才表示操作结束。

范例:编写服务器端

 

 1 package cn.Tony.netdemo.echo;
 2 
 3 import java.io.PrintStream;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 import java.util.Scanner;
 7 
 8 public class EchoServer {
 9     public static void main(String[] args) throws Exception{
10         ServerSocket server=new ServerSocket(8888);
11         Socket client=server.accept();
12         Scanner scan=new Scanner(client.getInputStream());
13         scan.useDelimiter("\n");
14         PrintStream out=new PrintStream(client.getOutputStream());
15         boolean flag=true;//作为循环的处理标记
16         while(flag) {//相当于一直循环
17             if(scan.hasNext()) {//现在客户端有数据发送
18                 String str=scan.next().trim();//防止有多与空格出现
19                 if("byebye".equalsIgnoreCase(str)) {//操作结束
20                     flag=false;//此时循环退出
21                     break;
22                 }
23                 out.println("ECHO:"+str);//做出回应
24             }
25         }
26         out.close();
27         scan.close();
28         server.close();
29     }
30 }

 

  随后编写客户端,客户端肯定需要由用户输入数据,自己来输入数据就需要使用System.in并且结合Scanner进行操作,

范例:

 1 package cn.Tony.netdemo.echo;
 2 
 3 import java.io.PrintStream;
 4 import java.net.Socket;
 5 import java.util.Scanner;
 6 
 7 
 8 public class EchoClient {
 9     public static void main(String[] args)throws Exception {
10         Socket client=new Socket("localhost",8888);
11         Scanner keyScan=new Scanner(System.in); //用户输入
12         keyScan.useDelimiter("\n");
13         Scanner netScan=new Scanner(client.getInputStream());
14         netScan.useDelimiter("\n");
15         PrintStream netOut=new PrintStream(client.getOutputStream());
16         boolean flag=true;
17         while(flag) {
18             System.out.println("请输入要发送的信息:");
19             if(keyScan.hasNext()) {
20                 String str=keyScan.next();
21                 netOut.println(str);//发送给服务器端
22                 if(netScan.hasNext()) {//服务器端有回应
23                     System.out.println(netScan.next());
24                 }
25                 if("byebye".equals(str)) {
26                     flag=false;
27                     break;
28                 }
29             }
30         }
31         keyScan.close();
32         netScan.close();
33         client.close();
34     }
35 }

  以上完成一个基础的完成,但是程序有一个问题,本程序为单线程,因为所有的操作都在主方法里面进行的。

 1 package cn.Tony.netdemo.echo;
 2 
 3 import java.io.PrintStream;
 4 import java.net.Socket;
 5 import java.util.Scanner;
 6 
 7 
 8 public class EchoClient {
 9     public static void main(String[] args)throws Exception {
10         Socket client=new Socket("localhost",8888);
11         Scanner keyScan=new Scanner(System.in); //用户输入
12         keyScan.useDelimiter("\n");
13         Scanner netScan=new Scanner(client.getInputStream());
14         netScan.useDelimiter("\n");
15         PrintStream netOut=new PrintStream(client.getOutputStream());
16         boolean flag=true;
17         while(flag) {
18             System.out.println("请输入要发送的信息:");
19             String str=null;
20             if(keyScan.hasNext()) {
21                  str=keyScan.next().trim();
22                 netOut.println(str);//发送给服务器端
23                 if(netScan.hasNext()) {//服务器端有回应
24                     System.out.println(netScan.next());
25                 }
26             }
27             if("byebye".equalsIgnoreCase(str)) {
28                 flag=false;
29                 break;
30             }
31         }
32         keyScan.close();
33         netScan.close();
34         client.close();
35     }
36 }

  要想解决当前问题就必须进行多线程处理。把每一个连接都封装在一个线程里面,这样处理起来就可以不受到单线程局限了

 1 package cn.Tony.netdemo.echo;
 2 import java.io.PrintStream;
 3 import java.net.ServerSocket;
 4 import java.net.Socket;
 5 import java.util.Scanner;
 6 public class EchoServer {
 7     private static class MyThread implements Runnable{
 8         private Socket client;
 9         public MyThread(Socket client) {
10             this.client=client;
11         }
12         @Override
13         public void run() {
14             try {
15             Scanner scan=new Scanner(client.getInputStream());
16             scan.useDelimiter("\n");
17             PrintStream out=new PrintStream(client.getOutputStream());
18             boolean flag=true;//作为循环的处理标记
19             while(flag) {//相当于一直循环
20                 if(scan.hasNext()) {//现在客户端有数据发送
21                     String str=scan.next().trim();//防止有多与空格出现
22                     if("byebye".equalsIgnoreCase(str)) {//操作结束
23                         out.println("BYEBYE!!!");//做出回应
24                         flag=false;//此时循环退出
25                         break;
26                     }
27                     out.println("ECHO:"+str);//做出回应
28                 }
29             }
30             out.close();
31             scan.close();
32             }catch(Exception e) {
33                 e.printStackTrace();
34             }
35         }
36     }
37     public static void main(String[] args) throws Exception{
38         ServerSocket server=new ServerSocket(8888);
39         boolean flag=true;
40         while(flag) {
41             Socket client=server.accept();
42             new Thread(new MyThread(client)).start();
43         }
44         server.close();
45     }
46 }

  实际上所有的服务器上,每一个用户的连接对服务器都是一个线程,线程通过指的就是对共享资源的控制

  网络编程的时代结束了,现在也不再去搞任何编程,

 

 

 

 

 

 

 

 

 

---恢复内容结束---

posted on 2019-03-18 23:18  朽木zidiao  阅读(215)  评论(0编辑  收藏  举报

导航