热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

多任务处理:服务器协议

服务器协议既然我们将要介绍的多任务服务器方法与特定的客户端-服务器协议相互独立,我们希望能够实现一个同时满足两者的协议。EchoProtocol中给出了回显协议的代码。这个类的静态方法h

服务器协议

 既然我们将要介绍的多任务服务器方法与特定的客户端-服务器协议相互独立,我们希望能够实现一个同时满足两者的协议。EchoProtocol中给出了回显协议的代码。这个类的静态方法handleEchoClient()中封装了对每个客户端的处理过程。除添加了写日志功能(马上会对其介绍)外,这段代码与TCPEchoServer.java中的连接处理部分几乎完全一致。该方法的参数是客户端Socket实例和Logger实例的引用。

 EchoProtocol类实现了Runnable接口(run()方法只是根据该实例的SocketLogger用,简单地调用handleEchoClient()方法),因此我们可以创建一个独立执行run()方法的线程。另外,服务器端的协议执行过程可以通过直接调用这个静态方法实现(为其传入SocketLogger实例的引用)。

 EchoProtocol.java

0 import java.io.IOException;

1 import java.io.InputStream;

2 import java.io.OutputStream;

3 import java.net.Socket;

4 import java.util.logging.Level;

5 import java.util.logging.Logger;

6

7 public class EchoProtocol implements Runnable {

8 private static final int BUFSIZE = 32; // Size (in bytes) of I/O buffer

9 private Socket clntSock; // Socket connect to client

10 private Logger logger; // Server logger

11

12 public EchoProtocol(Socket clntSock, Logger logger) {

13 this.clntSock = clntSock;

14 this.logger = logger;

15 }

16

17 public static void handleEchoClient(Socket clntSock, Logger logger) {

18 try {

19 // Get the input and output I/O streams from socket

20 InputStream in = clntSock.getInputStream();

21 OutputStream out = clntSock.getOutputStream();

22

23 int recvMsgSize; // Size of received message

24 int totalBytesEchoed = 0; // Bytes received from client

25 byte[] echoBuffer = new byte[BUFSIZE]; // Receive Buffer

26 // Receive until client closes connection, indicated by -1

27 while ((recvMsgSize = in.read(echoBuffer)) != -1) {

28 out.write(echoBuffer, 0, recvMsgSize);

29 totalBytesEchoed += recvMsgSize;

30 }

31

32 logger.info("Client " + clntSock.getRemoteSocketAddress() + ", echoed "

33 + totalBytesEchoed + " bytes.");

34

35 } catch (IOException ex) {

36 logger.log(Level.WARNING, "Exception in echo protocol", ex);

37 } finally {

38 try {

39 clntSock.close();

40 } catch (IOException e) {

41 }

42 }

43 }

44

45 public void run() {

46 handleEchoClient(clntSock, logger);

47 }

48 }

EchoProtocol.java

1.声明实现Runnable接口:第7 

2.类成员变量和构造函数:第8-15

每个EchoProtocol实例都包含了一个相应连接的套接字和对logger实例的引用。

3.handleEchoClient():第17-43

实现回显协议:

从套接字中获取输入/输出流:第20-21

接收和回显:第25-30

循环执行直到连接关闭(由read()方法返回值为-1指示),每次循环中在接收到数据后

就立即写回。

在日志中记录连续的详细信息:第32-33

同时记录远端的SocketAddress和回显的字节数。

异常处理:第36

将异常写入日志。

你的服务器每分钟将执行上千次客户端请求。现在有用户报告了一个问题。那么如何才能确定到底发生了什么呢?是不是服务器的问题呢?也许是客户端在破坏这个协议。为了处理这种情况,大部分的服务器都将它们的活动记录写入日志。这里我们只对写日志作非常基础的介绍,不过,你得知道还存在更多的日志记录功能以满足企业级需求。

 首先我们介绍Logger类,它代表了本地或远端的一个日志记录工具。通过该类的一个实例,我们就可以记录服务器的各种活动信息,就像在EchoProtocol中演示的那样。或许你会在服务器上使用多个日志记录器(logger),每个记录器以不同的方式负责不同的需求。例如,你可以有不同的日志记录器分别负责记录操作、安全和出错消息。在Java中,每个日志记录器由一个全局唯一的名字识别。按照如下代码调用Logger.getLogger()静态工厂方法即可获取一个Logger实例:

Logger logger = Logger.getLogger("practical"); 

这行代码用于获取名字为"practical"的记录器。如果这个名字的记录器不存在,则用这个名字创建一个新的记录器,否则,返回已存在的记录器实例。无论在程序中获取名字为"practical"的记录器多少次,都将返回同一个实例。

 有了日志记录器,需要记录什么内容呢?这取决于你要做什么。如果服务器在正常地运行,你可能不想将服务器执行的每一步都记录到日志中,因为记录日志是要消耗系统资源的,如为日志项分配存储空间,写日志需要占用服务器的处理时间等。另一方面,如果是为了调试,你可能就希望记录服务器执行的每一步。为了对不同情况进行处理,记录器中通常包含了日志项的等级或严格度的概念。Level类中就封装了消息的重要程度信息。每个Logger实例都有一个当前等级,每条日志消息也有对应的等级,低于Logger实例的当前等级的消息将被抛弃(即不写入日志)。每个等级都有一个对应的整数值,因此等级之间可以相互比较和排序。系统识别的Level实例共有7种,同时还能创建用户定义的等级,不过通常没有必要这样做。内置的等级(定义为Level类的静态字段)包括:severewarninginfoconfigfinefiner,和finest

 当你写日志的时候,消息又去哪儿呢?记录器将消息发送到一个或多个Handler实例中,该实例用来发布这些消息。默认情况,每个logger有一个ConsoleHandler用来将消息打印System.err中。你也可以为一个logger改变或添加handler(如FileHandler)。注意,与logger一样,每个handler也有自己的最小日志等级,因此要发布一条消息,它的等级必须同时高于loggerhandler的等级阈值。loggerhandler的可配置性很高,包括他们的最小等级。

 Logger对我们来说一个重要的特征是它是线程安全的(thread-safe),即可以在并行运行的不同线程中调用它的方法,而不需要在调用者中添加额外的同步措施。如果没有这个特征,由不同线程记录的不同消息将错乱无章地写到日志中。 

Logger: 查找/创建

static Logger getLogger(String name)

static Logger getLogger(String name, String

resourceBundleName) 

这些静态工厂方法返回指定名字的Logger实例,必要时创建新的实例。

 一旦有了logger,我就需要做的就是……写日志。Logger提供了从细粒度到粗粒度的日志记录工具,并能够区分消息的不同等级甚至消息的上下文。 

Logger: 记录日志消息

void severe(String msg)

void warning(String msg)

void info(String msg)

void config(String msg)

void fine(String msg)

void finer(String msg)

void finest(String msg)

void entering(String sourceClass, String sourceMethod)

void entering(String sourceClass, String sourceMethod,

Object param)

void entering(String sourceClass, String sourceMethod,

Object[] params)

void exiting(String sourceClass, String sourceMethod)

void exiting(String sourceClass, String sourceMethod, 

Object result)

void throwing(String sourceClass, String sourceMethod,

Throwable thrown)

void log(Level level, String msg)

void log(Level level, String msg, Throwable thrown)

severe()warning()等方法根据其名字对应等级,将给定的符合等级的消息写入日志。entering()exiting()方法在程序进入或退出给定类的指定方法时将记录写入日志。注意你也可以选择性地指定额外信息,如参数和返回值等。throwing()方法用于将指定方法所抛出的异常信息写入日志。log()方法提供了一种一般性的日志记录方式,该方法可以指定需要记录的消息等级和内容,并可以选择性地添加异常信息。当然还存在很多其他记录日志的方法,这里我们只提到了主要的几种。 我们可能希望能够通过设置最小记录等级或日志消息处理器的等级,来定制自己的记录器。

 Logger: 设置/获取日志的等级和处理器

Handler[] getHandlers()

void addHandler(Handler handler)

void removeHandler(Handler handler)

Level getLevel()

void setLevel(Level newLevel)

boolean isLoggable(Level level)

getHandlers()方法返回一个包含了和该记录器关联的所有日志处理器数组。addHandler()removeHandler()方法用于给该记录器添加或删除日志处理器。getLevel()setLevel()方法用于获取和设置日志记录的最小等级。isLoggable()方法则在该记录器能够记录所给定的等级的日志时返回true 

现在我们准备介绍一些不同的方法来实现并行服务器。

 

相关下载:

Java_TCPIP_Socket编程(doc)

http://download.csdn.net/detail/undoner/4940239

 

文献来源:

UNDONER(小杰博客) :http://blog.csdn.net/undoner

LSOFT.CN(琅软中国) :http://www.lsoft.cn

 


推荐阅读
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • importjava.util.ArrayList;publicclassPageIndex{privateintpageSize;每页要显示的行privateintpageNum ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
author-avatar
tuir
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有