java实现了简单的Echo服务程序分服务器和客户端
2016-06-22 22:15
645 查看
服务器程序
package simple.server; /* 所遇到的坑 1、现在是服务器和客户端可以建立链接,服务器可以把消息通过输出流发送到客户端显示, 但是客户端的数据不可以发送到服务器端显示。然后各种找,代码中加了很多的输出语句,查找现在执行到了哪里。 发现服务器程序不能输出客户端发送过来的信息,也不能将信息回显到客户端。找了很久,也在网络找了发现readLine函数 是以换行符位返回的判定规则。搜嘎,然后把所有通过流发送调用的write函数后都插入一个换行符。 2、在试验发现还不行,找到我的输出流都用了BufferedWriter缓存,write发送之后必须要强制刷新,flush()一下。才算到位啦。真是辛苦。 */ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { private static final int PORT = 8900; // 知名端口(0-1023)还会报权限不够的错误。 private ServerSocket serverSocket; public Server() throws IOException { this.serverSocket = new ServerSocket(PORT); System.out.println("服务器启动" + "在" + PORT + "端口监听链接请求"); } public String echo(String msg) { return "echo: " + msg; } //服务器主要的处理逻辑 public void service() { // Socket socket=null; while (true) { Socket socket = null; try { System.out.println("开始监听"); socket = serverSocket.accept(); System.out.println("New connection" + "accepted" + socket.getInetAddress() + ": " + socket.getPort()); BufferedReader br = getReader(socket); BufferedWriter bw = getWriter(socket); String msg = null; bw.write(socket.getInetAddress() + ": " + socket.getPort() + "你好\n"); // 强制flush,将数据推送到客户端哪里去。 bw.flush(); System.out.println("获得了输入流和输出流了"); while ((msg = br.readLine()) != null) { // 服务器读取客户端数据时候readline函数阻塞了, // 如果客户端断开了链接,说明到了流的末尾,将返回null, //或者一串字符串跟着换行符也将不在阻塞,string返回。 System.out.println("获得了" + socket.getInetAddress() + "数据:" + msg + "\t将回显回去"); bw.write(echo(msg));//回显 bw.newLine();// 这个操作也是必须的,相当于插入一个行分割符,readline方法用来判定一行字符串有没结束 bw.flush();// 刷新输出缓冲区 if (msg.equals("bye")) { System.out.println("链接断开,监听下一次链接"); break; } } // (!socket.isClosed()&& socket.isConnected())表示链接还在 if (!(!socket.isClosed() && socket.isConnected())) { System.out.println("链接断开,监听下一次链接"); } // System.out.println("没有进入while循环吗 "+msg); } catch (IOException e) { } finally { try {// 一次链接后把这个socket销毁。等待下一次的 //socket链接 if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } private BufferedReader getReader(Socket socket) throws IOException { InputStream ins = socket.getInputStream(); return new BufferedReader(new InputStreamReader(ins, "UTF-8")); } private BufferedWriter getWriter(Socket socket) throws IOException { OutputStream ous = socket.getOutputStream(); return new BufferedWriter(new OutputStreamWriter(ous, "UTF-8")); } public static void main(String arg[]) throws IOException { new Server().service(); } // 通过这个函数测试后,客户端函数可以发送数据到服务器进程中。发现了客户端那边发送过来时候flush了一下。 public void testClientReader() { try { Socket socket = serverSocket.accept(); BufferedReader br = getReader(socket); System.out.println(br.readLine()); } catch (IOException e) { } } }
客户端测试代码
package client.toserver; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; public class ClientDemo { private static final int PORT = 8900; private String host = "localhost"; private Socket socket; public ClientDemo() { try { this.socket = new Socket(host, PORT); System.out.println("客户端链接成功"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { new ClientDemo().talkToServer(); System.out.println("client over"); } // 测试写数据到服务器的连通性 public void testServerWriter() { BufferedWriter bWriter = getWriter(socket); try { bWriter.write("vincent ok"); bWriter.newLine(); bWriter.flush();// 这个动作非常重要 } catch (Exception e) { // TODO: handle exception } } public void talkToServer() { BufferedReader bReader = getReader(socket); BufferedWriter bWriter = getWriter(socket); BufferedReader localbr; String mString = null; // 构建本地客户端终端的输入流 try { localbr = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); // while (true) { // if ((mString = localBuRe.readLine()) != null) { // System.out.println("client print: " + mString); // bWriter.write(mString); // System.out.println("Server print: " + bReader.readLine()); // if (mString.equals("bye")) { // break; // } // } else { // break; // } // } System.out.println("进入while循环"); // System.out.println(bWriter == null ? "true" : "false"); // System.out.println(System.getProperty("line.")); System.out.println("server print " + bReader.readLine()); while ((mString = localbr.readLine()) != null) { // readLine方法必须读取到行分割符才返回读取。所以传递给输入流的字符串必须包含行分割符 System.out.println("client print " + mString); bWriter.write(mString); bWriter.newLine();// 插入一个行分隔符,作为服务器端readline函数判断这个字符串结束的标识 // 非常重要的是必须显式的将数据推送到服务器哪里去 bWriter.flush(); System.out.println("输出到server的数据"); // 读取到服务器的数据,readline方法是阻塞的 System.out.println("获得了服务器响应数据: " + "server print " + bReader.readLine()); if (mString.equals("bye")) { socket.close(); break; } } System.out.println("退出while循环"); } catch (Exception e) { // TODO: handle exception } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } private BufferedWriter getWriter(Socket socket) { try { OutputStream outputStream = null; BufferedWriter bWriter = null; outputStream = socket.getOutputStream(); bWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8")); return bWriter; } catch (Exception e) { // TODO: handle exception } return null; } private BufferedReader getReader(Socket socket) { try { InputStream ins = null; BufferedReader brReader = null; ins = socket.getInputStream(); brReader = new BufferedReader(new InputStreamReader(ins, "UTF-8")); return brReader; } catch (Exception e) { // TODO: handle exception } return null; } }
测试结果
在eclipse下开了两个窗口分别运行模拟服务器进程和客户端进程。左边是发起请求的客户端,右边是服务请求的服务器程序。
客户端程序需要退出交互只要输入bye字符串就可以退出,然后服务器程序等待下一个链接的客户端程序。服务器程序可以循环服务多个用户,但是一时间是只能服务一个客户进程的。
相关文章推荐
- Spring设计目标以及架构
- 《Thinkinginjava》第7章-复用类
- java参数传递(超经典)
- java死锁代码示例
- 07.Java 集合 - HashTable
- 1.spring-mvc 源代码(.jar)
- spring集合类型的setter注入的一个简单例子
- spring单例和多例详解。如何在单例中调用多例对象
- java动态代理
- java 基础知识问题集
- Eclipse项目导入Android Studio,.9图片报错解决办法
- JDK安装目录下的src
- java内存模型的理解
- Java中的重载与重写
- Java连接用windows身份验证SQLServer
- Swing Timer 的使用案例
- Lemon OA(开发版)系统在myeclipse上部署的完整过程
- 最受欢迎的Java第三方库
- java.lang包
- 【java虚拟机序列】java中的垃圾回收与内存分配策略