一、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. springboot-shiro chapter03 login

    简介:这一节主要是集成shiro进行鉴权, 用户登录/退出 环境: IDEA15+JDK1.8+Maven3+ 代码: https://git.oschina.net/xinshu/springboo ...

  2. 6、数据类型四:sets

    集合的基本特征:无序,唯一. 一个redis集合最多能存放232-1个集合元素.其强大之处在于它支持集合的“交.差.并”运算,而且能够快速的判断某个给定值是否在集合中. 1.基本命令: SADD ke ...

  3. Program Size: data=9.0 xdata=0 code=47

    data=47.0 编译器编译后,程序总共需要占用47字节的片内RAM空间.注意这个大小仅仅是累加而已,并未考虑各个块之间的空隙,也就是说实际占用的RAM空间可能多于此数值.xdata=0 程序未使用 ...

  4. Linux监控和安全运维 2.0 zabbix配置邮件告警

    1.发邮件启动postfix /etc/init.d/postfix start mail -s @qq.com < /etc/inittab mailq 查看发送结果 2.配置发邮件文件 mk ...

  5. U3D中的又一个坑

    using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; pu ...

  6. C# 发送和接受Get请求

    1.发送Get请求 public static string HttpGet(string Url, string postDataStr) { HttpWebRequest request = (H ...

  7. IDEA错误的忽略了智能补全代码,导致正确的代码自动提示不出来的问题

    标题说起来有点绕,当今大部分IDE都提供 Alt+Enter 呼出自动补全菜单的功能,IDEA也不例外,今天手残了一下,具体问题如下: 1. 通常我们键入一个自定义类时IDEA会自动提示为红色,表示缺 ...

  8. 380. Insert Delete GetRandom O(1) 设计数据结构:在1的时间内插入、删除、产生随机数

    [抄题]: Design a data structure that supports all following operations in average O(1) time. insert(va ...

  9. C程序之包含头文件

    在C程序中包含文件有以下两种方法: 方法一:#include<XXX.h> 这里的XXX一般是改动较小的标准库,用符号"<"和">"将要 ...

  10. Openssl oscp命令

    一.简介 ocsp,在线证书状态命,能够执行很多OCSP的任务,可以被用于打印请求文件和响应文件, 二.语法 openssl ocsp [-out file] [-issuer file] [-cer ...