例子来自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. [转帖]windows10彻底关闭Windows Defender的4种方法

    https://zhuanlan.zhihu.com/p/495107049 Windows Defender是windows10系统自带的杀毒软件.默认情况下它处于打开的状态.大多数第三方的杀毒软件 ...

  2. [转帖]Shell三剑客之sed

    目录 Shell三剑客 sed工具 sed 流编辑器的工作过程 sed命令格式与选项操作符 sed命令的常用选项 sed命令的打印功能 默认打印方式 sed命令的寻址打印 文本模式过滤行内容 sed的 ...

  3. [转帖]Dockerfile中CMD和ENTRYPOINT命令详解

    https://www.jb51.net/article/136264.htm   Dockerfile中的ENTRYPOINT指令和CMD指令都可以设置容器启动时要执行的命令,但用途是有略微不同的. ...

  4. [转帖]使用 TiFlash

    TiDB试用 来源:TiDB  浏览 490 扫码 分享 2021-04-20 20:57:48 使用 TiFlash 按表构建 TiFlash 副本 查看表同步进度 使用 TiDB 读取 TiFla ...

  5. 【转帖】QUIC协议简史

    QUIC简史 QUIC(Quick UDP Internet Connection)是谷歌推出的一套基于UDP的传输协议,它实现了TCP + HTTPS + HTTP/2的功能,目的是保证可靠性的同时 ...

  6. 神通奥斯卡数据库是否兼容Oracle, 以及参数修改的办法

    1. 最近公司要适配神通数据库, 但是因为一些功能异常.参数可能存在风险. 为了减少问题, 想着简单描述一下这些的处理. 开发和客户给的默认参数建议 1. 不选择 兼容oracle模式 2. 字符集选 ...

  7. RocketMQ—引言

    RocketMQ-引言 MQ介绍 在学习RocketMQ之前,我们先来看以下MQ的意思. MQ是Message Queue的首字母缩写. Message:意思为消息,在我们生活中可以是一句话/一个短信 ...

  8. go中bufio使用小结

    bufio 前言 例子 bufio 源码解析 Reader对象 实例化 ReadSlice ReadString ReadLine Peek Scanner Give me more data Err ...

  9. 《Java 面经手册》PDF,417页11.5万字,完稿!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 我膨胀了 ,在看了大部分以面试讲解的 Java 文章后,发现很多内容的讲解都偏向于翻 ...

  10. 香橙派上的eMMC分区

    准备工作 OrangePi Plus 2E(自带16G的eMMC存储,出厂默认eMMC中附带了Android系统,用于测试板子功能) Ubuntu16.04的TF卡 第一张方式: 该方式可以按需删除指 ...