一、Java中的服务器程序与多线程

  在Java之前,没有一种主流编程语言能够提供对高级网络编程的固有支持。在其他语言环境中,实现网络程序往往需要深入依赖于操作平台的网络API的技术中去,而Java提供了对网络支持的无平台相关性的完整软件包,使程序员没有必要为系统网络支持的细节而烦恼。

  Java软件包内在支持的网络协议为TCP/IP,也是当今最流行的广域网/局域网协议。Java有关网络的类及接口定义在java.net包中。客户端软件通常使用java.net包中的核心类Socket与服务器的某个端口建立连接,而服务器程序不同于客户机,它需要初始化一个端口进行监听,遇到连接呼叫,才与相应的客户机建立连接。Java.net包的ServerSocket类包含了编写服务器系统所需的一切。下面给出ServerSocket类的部分定义。

public class
ServerSocket
{
 public ServerSocket(int port)
 throws IOException ;
 public Socket accept() throws
IOException ;
 public InetAddress getInetAddress() ;
 public int getLocalPort() ;
 public void close() throws IOException ;
 public synchronized void setSoTimeout
(int timeout) throws SocketException ;
 public synchronized int getSoTimeout()
throws IOException ;
}

  ServerSocket构造器是服务器程序运行的基础,它将参数port指定的端口初始化作为该服务器的端口,监听客户机连接请求。Port的范围是0到65536,但0到1023是标准Internet协议保留端口,而且在Unix主机上,这些端口只有root用户可以使用。一般自定义的端口号在8000到16000之间。仅初始化了ServerSocket还是远远不够的,它没有同客户机交互的套接字(Socket),因此需要调用该类的accept方法接受客户呼叫。Accept()方法直到有连接请求才返回通信套接字(Socket)的实例。通过这个实例的输入、输出流,服务器可以接收用户指令,并将相应结果回应客户机。ServerSocket类的getInetAddress和getLocalPort方法可得到该服务器的IP地址和端口。setSoTimeout和getSoTimeout方法分别是设置和得到服务器超时设置,如果服务器在timout设定时间内还未得到accept方法返回的套接字实例,则抛出IOException的异常。

  Java的多线程可谓是Java编程的精华之一,运用得当可以极大地改善程序的响应时间,提高程序的并行性。在服务器程序中,由于往往要接收不同客户机的同时请求或命令,因此可以对每个客户机的请求生成一个命令处理线程,同时对各用户的指令作出反应。在一些较复杂的系统中,我们还可以为每个数据库查询指令生成单独的线程,并行对数据库进行操作。实践证明,采用多线程设计可以很好的改善系统的响应,并保证用户指令执行的独立性。由于Java本身是"线程安全"的,因此有一条编程原则是能够独立在一个线程中完成的操作就应该开辟一个新的线程。

  Java中实现线程的方式有两种,一是生成Thread类的子类,并定义该子类自己的run方法,线程的操作在方法run中实现。但我们定义的类一般是其他类的子类,而Java又不允许多重继承,因此第二种实现线程的方法是实现Runnable接口。通过覆盖Runnable接口中的run方法实现该线程的功能。本文例子采用第一种方法实现线程。

  二、多线程服务器程序举例

  以下是我们在项目中采用的多线程服务器程序的架构,可以在此基础上对命令进行扩充。本例未涉及数据库。如果在线程运行中需要根据用户指令对数据库进行更新操作,则应注意线程间的同步问题,使同一更新方法一次只能由一个线程调用。这里我们有两个类,receiveServer包含启动代码(main()),并初始化ServerSocket的实例,在accept方法返回用户请求后,将返回的套接字(Socket)交给生成的线程类serverThread的实例,直到该用户结束连接。

//类receiveServer
import java.io.*;
import java.util.*;
import java.net.*;

public class receiveServer{
 final int RECEIVE_PORT=9090; //该服务器的端口号
 //receiveServer的构造器public receiveServer() {ServerSocket rServer=null;
 //ServerSocket的实例
 Socket request=null;
 //用户请求的套接字Thread receiveThread=null;
 try{
  rServer=new ServerSocket(RECEIVE_PORT);
  //初始化ServerSocket System.out.println("Welcome to the
server!");
  System.out.println(new Date());
  System.out.println("The server is
ready!");
  System.out.println("Port: "+RECEIVE_PORT);
  while(true){ //等待用户请求 request=rServer.accept(); //接收客户机连接请求receiveThread=new serverThread(request);

  //生成serverThread的实例
  receiveThread.start();

  //启动serverThread线程
 }
}
catch(IOException e){
 System.out.println(e.getMessage()) ;
}
} public static void main(String args[]){ new receiveServer();

} //end of main} //end of class//类serverThreadimport java.io.*;

import java.net.*;
class serverThread extends Thread {Socket clientRequest;
//用户连接的通信套接字BufferedReader input;
//输入流PrintWriter output;
//输出流
public serverThread(Socket s) {
 //serverThread的构造器 this.clientRequest=s;
 //接收receiveServer传来的套接字 InputStreamReader reader;

 OutputStreamWriter writer;
 try{
  //初始化输入、输出流
  reader=new
InputStreamReader(clientRequest.getInputStream());
  writer=new
OutputStreamWriter(clientRequest.getOutputStream());
  input=new BufferedReader(reader);
  output=new PrintWriter(writer,true);
 }
 catch(IOException e){
System.out.println(e.getMessage());}
 output.println("Welcome to the
server!");
 //客户机连接欢迎词
 output.println("Now is: "+new
java.util.Date()+" "+
"Port:"+clientRequest.getLocalPort());
 output.println("What can I do for
you?");
}

public void run(){
 //线程的执行方法
 String command=null;
 //用户指令 String str=null;
 boolean done=false;
 while(!done){
  try{
   str=input.readLine();
   //接收客户机指令
  }catch(IOException e){
   System.out.println(e.getMessage());
 }
 command=str.trim().toUpperCase();

 if(str==null ||
command.equals("QUIT")) //命令quit结束本次连接
  done=true;
 else
if(command.equals("HELP")){
  //命令help查询本服务器可接受的命令
  output.println("query");
  output.println("quit");
  output.println("help");
 }
 else
if(command.startsWith("QUERY")){
  //命令
  query output.println("OK to query
something!");
 }//else if …….. //在此可加入服务器的其他指令
 else
if(!command.startsWith("HELP") &&
!command.startsWith("QUIT") &&
!command.startsWith("QUERY")){output.println("Command not
Found!
  Please refer to the HELP!"); }
}

//end of while

try
{
 clientRequest.close();
 //关闭套接字
}
catch(IOException e){
 System.out.println(e.getMessage());
}
command=null;
}

//end of run

  启动该服务器程序后,可用telnet machine port命令连接,其中machine为本机名或地址,port为程序中指定的端口。也可以编写特定的客户机软件通过TCP的Socket套接字建立连接。

用Java实现多线程服务器程序的更多相关文章

  1. java Socket多线程聊天程序

    参考JAVA 通过 Socket 实现 TCP 编程 参考java Socket多线程聊天程序(适合初学者) 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包 ...

  2. 【Java】对服务器程序的理解

    Login:------------->方法 Data:----->类.API数据 Collection:-------->集合 Data Source File: Database ...

  3. Socket 实现简单的多线程服务器程序

    **********服务器端************* public class ServerSocket{ public static void main(String[] args) throws ...

  4. 使用 acl_cpp 的 HttpServlet 类及服务器框架编写WEB服务器程序(系列文章)

    在 <用C++实现类似于JAVA HttpServlet 的编程接口 > 文章中讲了如何用 HttpServlet 等相关类编写 CGI 程序,于是有网友提出了 CGI 程序低效性,不错, ...

  5. Java实现Linux下服务器程序的双守护进程

    作者:Vinkn 来自http://www.cnblogs.com/Vinkn/ 一.简介 现在的服务器端程序很多都是基于Java开发,针对于Java开发的Socket程序,这样的服务器端上线后出现问 ...

  6. 《用Java写一个通用的服务器程序》02 监听器

    在一个服务器程序中,监听器的作用类似于公司前台,起引导作用,因此监听器花在每个新连接上的时间应该尽可能短,这样才能保证最快响应. 回到编程本身来说: 1. 监听器最好由单独的线程运行 2. 监听器在接 ...

  7. 《用Java写一个通用的服务器程序》01 综述

    最近一两年用C++写了好几个基于TCP通信类型程序,都是写一个小型的服务器,监听请求,解析自定义的协议,处理请求,返回结果.每次写新程序时都把老代码拿来,修改一下协议解析部分和业务处理部分,然后就一个 ...

  8. Java如何创建多线程服务器?

    在Java编程中,如何创建多线程服务器? 以下示例演示如何使用ServerSocket类的MultiThreadServer(socketname)方法和Socket类的ssock.accept()方 ...

  9. 批量远程执行linux服务器程序--基于paramiko(多线程版)

    批量远程执行linux服务器程序--基于paramiko paramiko模块是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接 具体安装方法这里不写,网 ...

随机推荐

  1. 六、配置github的pull request触发jenkins自动构建

    之前的配置,都是向master分支push操作触发jenkins进行构建,但是在一般的正常工作中,不会允许程序员直接向主分支推送代码:正常都是fork一个本地的分支,在本地分支调试完后,向主干分支提交 ...

  2. [js方法pk]之instanceof() vs isPrototypeOf() hasOwnProperty() vs propertyIsEnumerable()

    这几个方法在js的高级编程中经常用到,对于新手来说可能还不知道他们有什么区别,我把我的体会总结下来,供大家参考: 首先,定义一个对象: function Parent() {this.name = & ...

  3. Redis实战——phpredis扩展安装

    准备安装软件(download) 1> [redis]       http://redis.googlecode.com/files/redis-2.4.3.tar.gz 2> [php ...

  4. 一个简单的环境光shader

    关于shader的一个简短的历史 在DirectX8之前,GPU有一个固定的方法去变换顶点和像素,称为“固定管线”.这使得在将它们传递给GPU后,开发者不可能操作顶点和像素的变换. DirectX8介 ...

  5. java中执行子类的构造方法时,会不会先执行父类的构造方法

    会,在创建子类的对象时,jvm会首先执行父类的构造方法,然后再执行子类的构造方法,如果是多级继承,会先执行最顶级父类的构造方法,然后依次执行各级个子类的构造方法.

  6. 【原】Coursera—Andrew Ng机器学习—Week 8 习题—聚类 和 降维

    [1]无监督算法 [2]聚类 [3]代价函数 [4] [5]K的选择 [6]降维 Answer:本来是 n 维,降维之后变成 k 维(k ≤ n) [7] [8] Answer: 斜率-1 [9] A ...

  7. 第1章WCF简介(WCF全面解析读书笔记2)

    第1章 WCF简介 面向服务架构(SOA)是近年来备受业界关注的一个主题,它代表了软件架构的一种方向.顺应SOA发展潮流,微软于2006年年底推出了一种新的分布式通信框架Windows Communi ...

  8. mysql默认字符编码设置教程:my.ini设置字符编码

    在mysql的安装目录下找到my.ini,如果没有就把my-medium.ini复制为一个my.ini即可. 打开my.ini以后, [client] default-character-set=ut ...

  9. cdoj915-方老师的分身 II (长度不小于k的最短路)【spfa】

    http://acm.uestc.edu.cn/#/problem/show/915 方老师的分身 II Time Limit: 10000/5000MS (Java/Others)     Memo ...

  10. css3中的transform、transition、translate、animation(@keyframes)的区别

    一.前言 在CSS中,我们经常会使用到transform.transition.translate.animation(@keyframes)这些长得相似,又不好区分的属性(值).每当需要使用它们,都 ...