zoukankan      html  css  js  c++  java
  • Java知识回顾 (14)网络编程

    本资料来自于runoob,略有修改。

    网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

    java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。

    Socket 编程

    套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。

    当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。

    java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

    以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

    • 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

    • 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

    • 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

    • Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。

    • 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

    连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

    TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。

    DEMO

    客户端

    // 文件名 GreetingClient.java
     
    import java.net.*;
    import java.io.*;
     
    public class GreetingClient
    {
       public static void main(String [] args)
       {
          String serverName = args[0];
          int port = Integer.parseInt(args[1]);
          try
          {
             System.out.println("连接到主机:" + serverName + " ,端口号:" + port);
             Socket client = new Socket(serverName, port);
             System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
             OutputStream outToServer = client.getOutputStream();
             DataOutputStream out = new DataOutputStream(outToServer);
     
             out.writeUTF("Hello from " + client.getLocalSocketAddress());
             InputStream inFromServer = client.getInputStream();
             DataInputStream in = new DataInputStream(inFromServer);
             System.out.println("服务器响应: " + in.readUTF());
             client.close();
          }catch(IOException e)
          {
             e.printStackTrace();
          }
       }
    }

    服务端

    // 文件名 GreetingServer.java
     
    import java.net.*;
    import java.io.*;
     
    public class GreetingServer extends Thread
    {
       private ServerSocket serverSocket;
       
       public GreetingServer(int port) throws IOException
       {
          serverSocket = new ServerSocket(port);
          serverSocket.setSoTimeout(10000);
       }
     
       public void run()
       {
          while(true)
          {
             try
             {
                System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
                Socket server = serverSocket.accept();
                System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
                DataInputStream in = new DataInputStream(server.getInputStream());
                System.out.println(in.readUTF());
                DataOutputStream out = new DataOutputStream(server.getOutputStream());
                out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "
    Goodbye!");
                server.close();
             }catch(SocketTimeoutException s)
             {
                System.out.println("Socket timed out!");
                break;
             }catch(IOException e)
             {
                e.printStackTrace();
                break;
             }
          }
       }
       public static void main(String [] args)
       {
          int port = Integer.parseInt(args[0]);
          try
          {
             Thread t = new GreetingServer(port);
             t.run();
          }catch(IOException e)
          {
             e.printStackTrace();
          }
       }
    }

    阻塞和非阻塞网络编程

    BIO(Blocking IO: 同步阻塞的编程方式

    BIO编程方式通常是在JDK1.4版本之前常用的编程方式。编程实现过程为:首先在服务端启动一个ServerSocket来监听网络请求,客户端启动Socket发起网络请求,默认情况下ServerSocket回建立一个线程来处理此请求,如果服务端没有线程可用,客户端则会阻塞等待或遭到拒绝。

    NIO (Unblocking IO): 同步非阻塞的编程方式

    NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题,NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。也就是说,这个时候,已经不是一个连接就要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。

    AIO(Asynchronous IO: 异步非阻塞的编程方式

    与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。在JDK1.7中,这部分内容被称作NIO.2,主要在java.nio.channels包下增加了下面四个异步通道:AsynchronousSocketChannel、AsynchronousServerSocketChannel、AsynchronousFileChannel、AsynchronousDatagramChannel

    bio示例

    public class Server {
    
        public static void main(String[] args) {
            int port = genPort(args);
            
            ServerSocket server = null;
            ExecutorService service = Executors.newFixedThreadPool(50);
            
            try{
                server = new ServerSocket(port);
                System.out.println("server started!");
                while(true){
                    Socket socket = server.accept();
                    
                    service.execute(new Handler(socket));
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                if(server != null){
                    try {
                        server.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                server = null;
            }
        }
        
        static class Handler implements Runnable{
            Socket socket = null;
            public Handler(Socket socket){
                this.socket = socket;
            }
            @Override
            public void run() {
                BufferedReader reader = null;
                PrintWriter writer = null;
                try{
                    
                    reader = new BufferedReader(
                            new InputStreamReader(socket.getInputStream(), "UTF-8"));
                    writer = new PrintWriter(
                            new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
                    String readMessage = null;
                    while(true){
                        System.out.println("server reading... ");
                        if((readMessage = reader.readLine()) == null){
                            break;
                        }
                        System.out.println(readMessage);
                        writer.println("server recive : " + readMessage);
                        writer.flush();
                    }
                }catch(Exception e){
                    e.printStackTrace();
                }finally{
                    if(socket != null){
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    socket = null;
                    if(reader != null){
                        try {
                            reader.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    reader = null;
                    if(writer != null){
                        writer.close();
                    }
                    writer = null;
                }
            }
            
        }
        
        private static int genPort(String[] args){
            if(args.length > 0){
                try{
                    return Integer.parseInt(args[0]);
                }catch(NumberFormatException e){
                    return 9999;
                }
            }else{
                return 9999;
            }
        }
        
    }
    server

    client

    public class Client {
        public static void main(String[] args) {
            String host = null;
            int port = 0;
            if(args.length > 2){
                host = args[0];
                port = Integer.parseInt(args[1]);
            }else{
                host = "127.0.0.1";
                port = 9999;
            }
            
            Socket socket = null;
            BufferedReader reader = null;
            PrintWriter writer = null;
            Scanner s = new Scanner(System.in);
            try{
                socket = new Socket(host, port);
                String message = null;
                
                reader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream(), "UTF-8"));
                writer = new PrintWriter(
                        socket.getOutputStream(), true);
                while(true){
                    message = s.nextLine();
                    if(message.equals("exit")){
                        break;
                    }
                    writer.println(message);
                    writer.flush();
                    System.out.println(reader.readLine());
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                socket = null;
                if(reader != null){
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                reader = null;
                if(writer != null){
                    writer.close();
                }
                writer = null;
            }
        }
    }
    View Code

    UDP简单示例

    服务端

    public class Server {
        public static void main(String[] args) {
            try {
                DatagramSocket server = new DatagramSocket(5060);
                DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
                server.receive(packet);
                System.out.println(packet.getAddress().getHostName() + "(" + packet.getPort() + "):" + new String(packet.getData()));
                packet.setData("Hello Client".getBytes());
                packet.setPort(5070);
                packet.setAddress(InetAddress.getLocalHost());
                server.send(packet);
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    View Code

    客户端

    public class Client {
        public static void main(String[] args){
            try {
                DatagramSocket client = new DatagramSocket(5070);
                DatagramPacket packet = new DatagramPacket(new byte[1024],1024);
                packet.setPort(5060);
                packet.setAddress(InetAddress.getLocalHost());
                packet.setData("Hello Server".getBytes());
                client.send(packet);
                client.receive(packet);
                System.out.println(packet.getAddress().getHostName() + "(" + packet.getPort() + "):" + new String(packet.getData()));
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    View Code
  • 相关阅读:
    PHP与Web页面的交互
    PHP数组和数据结构(下)未完。。。。
    PHP数组和数据结构(上)
    网络
    单列模式(饿汉模式和懒汉模式)
    C++动态内存管理
    基础I/O
    进程程序替换(自主实现shell)
    进程控制
    调研task_struct结构体
  • 原文地址:https://www.cnblogs.com/arxive/p/11627669.html
Copyright © 2011-2022 走看看