例子来自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. Oracle12c新增max_idle_time参数的学习与感触

    Oracle12c新增max_idle_time参数的学习与感触 TLDR 其实任何软件出了新版本.readme 是很重要的. 尤其是数据库, 涉及到底层问题的. 比如这次遇到的Oracle的max_ ...

  2. [转帖]Django10——从db.sqlite3迁移到MySQL

    https://blog.csdn.net/weixin_47197906/article/details/124889477 文章目录 1.查看Django支持的数据库 2.修改数据库配置 1.查看 ...

  3. jcmd的简要分析命令

    jcmd的简要分析命令 背景 端午加班一整天. 回到家同事让他们抓取一下堆栈信息好进行分析 连上VPN后就进行了一下处理. 自己简单看了下堆栈的总数等信息. 同事使用工具进行了分析. 我这边其实下过很 ...

  4. [转帖]SYSTEMD 配置文件

    https://www.cnblogs.com/xiexun/p/13643952.html [Unit]区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系 ...

  5. 非root用户搭建sftp以及进行简要使用的介绍

    sftp的简介 关于sftp sftp是Secure FileTransferProtocol的缩写,安全文件传送协议,可以为传输文件提供一种安全的加密方法. sftp与 ftp有着几乎一样的语法和功 ...

  6. ZCube:在我的优惠券中的落地实践 | 京东云技术团队

    ​ 前言 我的优惠券作为营销玩法的一种运营工具,在营销活跃场中起到很至关重要的作用.如何更加高效的赋能业务,助理业务发展,灵活扩展业务,是我们一直追求和思考的方向 一.背景 1.1 现状 营销中台作为 ...

  7. rust入坑指南之ownership

    作者:京东零售 王梦津 I. 前言 Rust,不少程序员的白月光,这里我们简单罗列一些大牛的评价. Linus Torvalds:Linux内核的创始人,对Rust的评价是:"Rust的主要 ...

  8. 如何写RN样式 如何写RN组件 如何满屏 如何使用变量

    app.js 文本水平居中了哈 控制文本的大小 字体颜色等 只有在文本元素上去控制哈 import React from 'react'; import {View, Text, StyleSheet ...

  9. vs2019系统内置方法无提示

    有个同事问我为什么他的vs编写C#代码,对于引用System.dll中的方法,鼠标移上去没有方法的使用说明或接口注释,具体可以看下面的截图,而我绝大多数情况下是使用Rider开发,并没有遇到这个问题, ...

  10. vim 从嫌弃到依赖(20)——global 命令

    在前面的文章中,我们介绍了如何进行查找和替换,而替换是建立在查找基础之上的一个简单的应用,它只是将匹配文本修改为另一个.那么vim中还能针对匹配上的文本做哪些操作呢?在本篇文章中我们来对这个问题进行探 ...