java实现最简单的客户服务器通信例子

  • Post author:
  • Post category:java


  1. 客户/服务器通信模式

    TCP/UDP协议推动了客户/服务器通信模式的广泛运用。在通信个进程中,一个进程为客户进程,另一个为服务器进程。客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求。如下图所示,通常,一个服务器进程会同时与多个客户端进程服务,图中进程B1同时为客户进程A1、A2和B2提供服务。以下伪代码演示了服务器进程的大致工作流程:

while(true){
    监听端口,等待客户请求;
    响应客户请求;
    }
  1. 用java编写客户/服务器程序

    java网络程序都建立在tcp/ip协议基础上,致力于实现应用层。传应用层提供了套接字Socket接口,Socket封装了下层的数据传输细节,应用层的程序通过Socket来建立与远程主机的连接,以及进行数据传输。

    站在应用层的角度,两个进程之间的一次通信过程从建立连接开始,接着交换数据,到断开连接结束。Socket可看做通信两端的收发器,进程通过Socket来收发数据,如图所示

    这里写图片描述

    3.创建EchoServer
package 最简单的客户服务器例子;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class EchoServer {
    private int port=8888;
    private ServerSocket serverSocket;

    /*
    服务器通过一直监听端口,来接受客户程序的连接请求。
    在服务器程序中需要先创建一个ServerSocket对象,在
    构造方法中指定监听的端口。构造方法负责在操作系统中
    把当前进程注册为服务器进程。
     */
    public EchoServer() throws IOException {
        serverSocket=new ServerSocket(port);
        System.out.println("服务器已经启动,,,");
    }

    public static void main(String[] args) throws IOException {
        new EchoServer().service();
    }

    private void service()  {
        while (true){
            Socket socket=null;
            try {
                /*
                服务器程序接下来调用serverSocket对象的accept()方法
                ,该方法一直监听端口,等待客户的连接请求,如果
                接收到一个连接请求,该方法就返回一个Socket对象
                这个Socket对象与客户端的Socket对象形成了一条
                通信线路。
                 */
                socket=serverSocket.accept();
                System.out.println("接受到客户端连接:"+socket.getInetAddress());

                /*
                Socket类提供了getInputStream()和getOutputStream()方法,分别返回
                输入流InputStream对象和输出流OutputStream对象。程序只需要向
                输出流写数据,就能向对方发送数据;
                只需要从输入流读数据就能接受来自对方的数据。
                 */

                //Scanner和PrintWriter都是带缓冲的流,能够读入和写出一行数据
                Scanner scanner=new Scanner(socket.getInputStream());
                //参数true表示每写一行,PrintWriter缓存就自动溢出,把数据写到目的地
                PrintWriter printWriter=new PrintWriter(socket.getOutputStream(),true);
                String msg=null;
                while ((msg=scanner.nextLine())!=null){
                    System.out.println("收到:"+msg);
                    printWriter.println("echo:"+msg);
                    if (msg.equals("bye")){
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (socket!=null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

EchoServer类最主要的方法是service()方法,他不断等待客户的连接请求,当serverSocket.accept()方法返回一个Socket对象时就意味着与一个客户端建立了连接。当客户端发来“bye”时,就会结束与客户的通信,调用socket.close()方法断开连接。

4.创建EchoClient

package 最简单的客户服务器例子;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class EchoClient {
    /*
    在EchoClient程序中,为了能与EchoServer通信,需要先建立一个
    Socket对象
     */
    private String host="localhost";//host表示EchoServer进程所在的主机的名字,当取值为localhost时,表示EchoClient和EchoServer进程运行在同一个主机上
    private int port=8888;//参数port表示EchoServer进程监听的端口
    private Socket socket;

    public static void main(String[] args)throws IOException{
        new EchoClient().talk();
    }

    //如果Socket创建成功,就表示客户端和服务器端建立了连接
    public EchoClient() throws IOException {
        socket=new Socket(host,port);
    }

    private void talk(){
        try (//Socket socket=new Socket(host,port);
             PrintWriter printWriter = new PrintWriter(socket.getOutputStream(),true);
             Scanner scanner=new Scanner(socket.getInputStream());
             Scanner localScanner=new Scanner(System.in)) {
            String line=null;
            while (localScanner.hasNextLine()){
                line=localScanner.nextLine();
                printWriter.println(line);
                System.out.println(scanner.nextLine());
                if (line.equals("bye"))
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在EchoClient类中,最主要的方法是他talk()方法。该方法不断的读取用户从控制台输入的字符串,然后把它发送给EchoServer,再把EchoServer返回的字符串打印到控制台。如果用户输入的是“bye”,就会结束与EchoSever的通信,调用socket.close();方法断开连接。


在客户进程中,Socket对象包含了本地及对方服务器进程的地址和端口信息,在服务器进程中,Socket对象也包含了本地以及对方客户进程的地址和端口信息。客户进程允许建立多个连接,每个连接都有唯一的端口。在编写网络程序时,一般显示的为服务器程序中的SeverSocket设置端口,而不必考虑客户进程所使用的端口。


5.小结

java程序致力于实现应用层。传输层向应用层提供了Socket接口,Socket封装了下层的数据传输细节,其应用层程序通过建立Socket来建立与远程主机的连接,以及进行数据传输。



版权声明:本文为qq_34444097原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。