例子来自Java官方教程,稍作调整。

上一篇介绍了单客户端访问的Server实现,这一篇实现的是多个客户端请求服务端,根据服务端提示进行一系列操作。

协议类(和系列三一样没变):

package com.dylan.socket;

/**
* @author xusucheng
* @create 2017-12-24
**/
public class KnockKnockProtocol {
private static final int WAITING = 0;
private static final int SENTKNOCKKNOCK = 1;
private static final int SENTCLUE = 2;
private static final int ANOTHER = 3; private static final int NUMJOKES = 5; private int state = WAITING;
private int currentJoke = 0; private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who", "Who" };
private String[] answers = { "Turnip the heat, it's cold in here!",
"I didn't know you could yodel!",
"Bless you!",
"Is there an owl in here?",
"Is there an echo in here?" }; public String processInput(String theInput) {
String theOutput = null; if (state == WAITING) {
theOutput = "Knock! Knock!";
state = SENTKNOCKKNOCK;
} else if (state == SENTKNOCKKNOCK) {
if (theInput.equalsIgnoreCase("Who's there?")) {
theOutput = clues[currentJoke];
state = SENTCLUE;
} else {
theOutput = "You're supposed to say \"Who's there?\"! " +
"Try again. Knock! Knock!";
}
} else if (state == SENTCLUE) {
if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) {
theOutput = answers[currentJoke] + " Want another? (y/n)";
state = ANOTHER;
} else {
theOutput = "You're supposed to say \"" +
clues[currentJoke] +
" who?\"" +
"! Try again. Knock! Knock!";
state = SENTKNOCKKNOCK;
}
} else if (state == ANOTHER) {
if (theInput.equalsIgnoreCase("y")) {
theOutput = "Knock! Knock!";
if (currentJoke == (NUMJOKES - 1))
currentJoke = 0;
else
currentJoke++;
state = SENTKNOCKKNOCK;
} else {
theOutput = "Bye.";
state = WAITING;
}
}
return theOutput;
}
}

服务器端:

package com.dylan.socket;

import java.io.IOException;
import java.net.ServerSocket; /**
* @author xusucheng
* @create 2017-12-24
**/
public class KKMultiServer {
private static final int PORT = 8858;
public static void main(String[] args) {
boolean listening = true; try (ServerSocket serverSocket = new ServerSocket(PORT)) {
while (listening) {
new KKMultiServerThread(serverSocket.accept()).start();
}
} catch (IOException e) {
System.err.println("Could not listen on port " + PORT);
System.exit(-1);
}
}
}

服务器多线程类(核心):

package com.dylan.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket; /**
* @author xusucheng
* @create 2017-12-24
**/
public class KKMultiServerThread extends Thread{
private Socket socket = null; public KKMultiServerThread(Socket socket) {
super("KKMultiServerThread");
this.socket = socket;
} public void run() { try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
) {
String inputLine, outputLine;
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine); while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye."))
break;
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

客户端:

package com.dylan.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException; /**
* @author xusucheng
* @create 2017-12-24
**/
public class KnockKnockClient {
private static final String HOST="127.0.0.1";
private static final int PORT=8858; public static void main(String[] args) throws IOException { /*if (args.length != 2) {
System.err.println(
"Usage: java EchoClient <host name> <port number>");
System.exit(1);
} String hostName = args[0];
int portNumber = Integer.parseInt(args[1]);*/ try (
Socket kkSocket = new Socket(HOST, PORT);
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(kkSocket.getInputStream()));
) {
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser; while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break; fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + HOST);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " +
HOST);
System.exit(1);
}
}
}

Java Socket编程系列(四)开发支持多客户端访问的Server的更多相关文章

  1. java并发编程系列四、AQS-AbstractQueuedSynchronizer

    什么是AbstractQueuedSynchronizer?为什么我们要分析它?  AQS:抽象队列同步器,原理是:当多个线程去获取锁的时候,如果获取锁失败了,当前线程就会被打包成一个node节点放入 ...

  2. 《Java 8实战》读书笔记系列——第三部分:高效Java 8编程(四):使用新的日期时间API

    https://www.lilu.org.cn/https://www.lilu.org.cn/ 第十二章:新的日期时间API 在Java 8之前,我们常用的日期时间API是java.util.Dat ...

  3. 20182332 实验四《Java Socket编程 》实验报告

    20182332 实验肆<数据结构与面向对象程序设计>实验报告 课程:<程序设计与数据结构> 班级: 1823 姓名: 盛国榕 学号:20182332 实验教师:王志强 实验日 ...

  4. Java并发编程系列-(5) Java并发容器

    5 并发容器 5.1 Hashtable.HashMap.TreeMap.HashSet.LinkedHashMap 在介绍并发容器之前,先分析下普通的容器,以及相应的实现,方便后续的对比. Hash ...

  5. Java并发编程系列-(7) Java线程安全

    7. 线程安全 7.1 线程安全的定义 如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的. 类的线程安全表现为: 操作的原子性 内存的可见性 不 ...

  6. Java Socket编程题库

    一.    填空题 ___ IP地址____用来标志网络中的一个通信实体的地址.通信实体可以是计算机,路由器等. 统一资源定位符URL是指向互联网"资源"的指针,由4部分组成:协议 ...

  7. Java并发编程系列-(6) Java线程池

    6. 线程池 6.1 基本概念 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题:如果并发的请求数 ...

  8. Java基础:三步学会Java Socket编程

    Java基础:三步学会Java Socket编程 http://tech.163.com 2006-04-10 09:17:18 来源: java-cn 网友评论11 条 论坛        第一步 ...

  9. 如何为可扩展系统进行Java Socket编程

    从简单I/O到异步非阻塞channel的Java Socket模型演变之旅 上世纪九十年代后期,我在一家在线视频游戏工资工作,在哪里我主要的工作就是编写Unix Unix Berkley Socket ...

  10. Java Socket 编程指南

    Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一.如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都是基于Socket实现的.本文会介绍一下基于TCP/IP的S ...

随机推荐

  1. Python学习之十六_virsh批量获取虚拟机IP地址的方法

    Python学习之十六_virsh批量获取虚拟机IP地址的方法 Linux命令说明 for j in \ $(for i in `virsh list |grep -v Id |grep runnin ...

  2. [转帖]Web技术(六):QUIC 是如何解决TCP 性能瓶颈的?

    文章目录 一.QUIC 如何解决TCP的队头阻塞问题? 1.1 TCP 为何会有队头阻塞问题 1.2 QUIC 如何解决队头阻塞问题 1.3 QUIC 没有队头阻塞的多路复用 二.QUIC 如何优化T ...

  3. [转帖]利用Python调用outlook自动发送邮件

    ↓↓↓欢迎关注我的公众号,在这里有数据相关技术经验的优质原创文章↓↓↓ 使用Python发送邮件有两种方式,一种是使用smtp调用邮箱的smtp服务器,另一种是直接调用程序直接发送邮件.而在outlo ...

  4. [转帖]VCSA6.7证书过期后的处置方法

    0x00 环境说明 一台测试的ESXI主机,元旦之后已然发现证书已过期,具体现象:VCenter无法登录,一直提示输入用户名和密码,ESXI主机web页面无法登录.重启VC以后,报故障503错误. / ...

  5. [转帖]并发控制- sched_yield 函数

    函数说明 函数原型 #include <sched.h> int sched_yield(void); 1 2 sched_yield的作用是让出处理器,调用时会导致当前线程放弃CPU,进 ...

  6. Notepad++ 显示空格

    公司里面用yaml 文件经常会出现一些奇怪的问题... 今天又遇到了//全角空格 显示的长度一样 但是实际上 yaml文件解析的不对..notepad++ ---> 视图--->显示符号- ...

  7. Docker搭建SvnServer

    下载svn-server官方镜像 docker pull garethflowers/svn-server 运行svn-server容器 docker run -v /home/svn:/var/op ...

  8. node中的fs模块和http模块的学习

    读取文件 fs 模块 第1个参数就是要读取的文件路径 第2个参数是一个回调函数(error,data)=>{} error 如果读取失败,error 就是错误对象 如果读取成功,error 就是 ...

  9. vue3跟新视图遇见神奇现象

    场景描述 今天遇见一个问题, tableAllFun 函数中写了一个 index=1; 然后在 otherAllFun 函数中去改变这个index=2的值 奇怪的事情发生了 在视图index展示的值是 ...

  10. 过滤器filters对时间格式的处理

    在表格中,我们经常会对时间格式进行处理: 这个时候,我们就可以使用过滤器了. 过滤器是不会,改变原始值 {{ mess | dotime }} {{ mess | do2time }} mess: & ...