`

socket编程(三)--服务器端实现多线程处理客户端请求并且将客户请求放在连接池中

阅读更多

需求:通socket编程(一)的需求

该实例中,客户端可能会有多个,服务器的处理器也会有多个,该情形类似于消费者在超市结账的过程,

假设固定有5个收银员,而消费者不确定:

如果开始没有消费者来结账,那么所有的收银员都处于等待状态;

如果有一个消费者来结账,那么随即会有一个收银员来处理,其他的收银员仍处于等待状态;

如果有大于一个小于6个的消费者来结账,那么收银员都会随即进行处理;

如果有大于5个的消费者在等待,就需要排队了(这也就是要说的连接池即客户端的请求链接放置的地方,把客户请求放在这个池子里)

 

客户端:

package com.socket.clientsocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class Sclient {

	/**
	 * @param args
	 */
	
	protected BufferedReader socketReader;
	protected PrintWriter socketWriter;
	protected String hostIp;
	protected int hostPort;
	
	
	public Sclient(String ahostIp,int ahostPort){
		this.hostIp = ahostIp;
		this.hostPort = ahostPort;
		
	}
	public void setUpConnection(){
	
		try {
			//1.创建Socket,建立连接
			Socket socket = new Socket(hostIp,hostPort);
			//2.获取输入流和输出流,并进行封装
			socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			socketWriter = new PrintWriter(socket.getOutputStream());
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	public void tearDownConnection(){
		
		try {
			socketReader.close();
			socketWriter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	//根据需求,对流进行处理
	public String getFile(String fileNameToGet){
		StringBuffer sb = new StringBuffer();
		socketWriter.println(fileNameToGet);
		socketWriter.flush();
		String line = null;
		try {
			while((line = socketReader.readLine()) != null){
				sb = sb.append(line + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	public static void main(String[] args) {
		//创建客户端
		Sclient client = new Sclient("198.27.0.166",8200);
		//建立连接
		client.setUpConnection();
		//需求操作
		String content = client.getFile("c:\\log.txt");
		//关闭连接
		client.tearDownConnection();
	}

}

 服务器端:

package com.socket.poolSocketServer;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;

public class PooledRemoteFileServer {

	/**
	 * @param args
	 */
	protected int maxConnections;
    protected int listenPort;
    protected ServerSocket serverSocket;
    public PooledRemoteFileServer(int aListenPort, int maxConnections) {
        listenPort = aListenPort;
        this.maxConnections = maxConnections;
    }
    public void acceptConnections() {
        try {
            ServerSocket server = new ServerSocket(listenPort, 5);
            Socket incomingConnection = null;
            while (true) {
                incomingConnection = server.accept();
                handleConnection(incomingConnection);
            }
        } catch (BindException e) {
            System.out.println("Unable to bind to port " + listenPort);
        } catch (IOException e) {
            System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
        }
    }
    protected void handleConnection(Socket connectionToHandle) {
        PooledConnectionHandler.processRequest(connectionToHandle);
    }
    public static void main(String[] args) {
        PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
        server.setUpHandlers();
        server.acceptConnections();
    }
    public void setUpHandlers() {
    	//可以把这些线程放到一个数组当中,来进行统一管理
        for (int i = 0; i < maxConnections; i++) {
            PooledConnectionHandler currentHandler = new PooledConnectionHandler();
            new Thread(currentHandler, "Handler " + i).start();
        }
    }



}
 

连接池处理器:

package com.socket.poolSocketServer;

import java.io.*;
import java.net.*;
import java.util.*;

public class PooledConnectionHandler implements Runnable {
    protected Socket connection;
    //静态变量,即所有对象共享该变量
    //以该类为目标创建的线程,将共同等待这个连接池,
    //一旦该连接池中有对象,则通知等待的线程
    protected static List pool = new LinkedList();
    public PooledConnectionHandler() {
    }
    public void handleConnection() {
        try {
            PrintWriter streamWriter = new PrintWriter(connection.getOutputStream());
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

            String fileToRead = streamReader.readLine();
            BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));

            String line = null;
            while ((line = fileReader.readLine()) != null)
                streamWriter.println(line);

            fileReader.close();
            streamWriter.close();
            streamReader.close();
        } catch (FileNotFoundException e) {
            System.out.println("Could not find requested file on the server.");
        } catch (IOException e) {
            System.out.println("Error handling a client: " + e);
        }
    }
    //向连接池中添加连接对象,可以在此处控制任务的最大数目(类似超市中待结账的消费者)
    //而等待中的线程类似N多结账的窗口
    public static void processRequest(Socket requestToHandle) {
    	//对共享对象操作时(增加,删除,修改),要考虑到同步
    	//获取互斥锁
        synchronized (pool) {
            pool.add(pool.size(), requestToHandle);
            pool.notifyAll();
        }
    }
    public void run() {
    	//条件可以为一个boolean类型的变量,以便停止线程
        while (true) {
        	//获取互斥锁
            synchronized (pool) {
                while (pool.isEmpty()) {
                    try {
                    	//调用此方法的时候,会放弃对象锁
                        pool.wait();
                    } catch (InterruptedException e) {
                        return;
                    }
                }
                connection = (Socket) pool.remove(0);
            }
            handleConnection();
        }
    }
}

 
分享到:
评论

相关推荐

    Linux高性能服务器编程

    14.7 线程同步机制包装类 14.8 多线程环境 14.8.1 可重入函数 14.8.2 线程和进程 14.8.3 线程和信号 第15章 进程池和线程池 15.1 进程池和线程池概述 15.2 处理多客户 15.3 半同步半异步进程池实现 15.4 ...

    JAVA面试题最全集

    客户端游标与服务器端游标的区别? 83.动态游标与静态游标的区别? 84.dotnet由哪几个基本框架组成? 85.Oracle中SGA是什么? 86.web servers是什么? 87.UNIX中QT是什么意思? 88.在软件开发生命周期中的哪个阶段...

    java面试宝典

    70、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 17 71、启动一个线程是用run()还是start()? 17 72、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 18 73...

    JAVA上百实例源码以及开源项目源代码

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    JAVA上百实例源码以及开源项目

     当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。  QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...

    千方百计笔试题大全

    70、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 17 71、启动一个线程是用run()还是start()? 17 72、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 18 73...

    Java范例开发大全 (源程序)

     第13章 多线程编程(教学视频:121分钟) 405  13.1 多线程的五种基本状态 405  实例222 启动线程 405  实例223 参赛者的比赛生活(线程休眠唤醒) 407  实例224 资源搜索并下载(线程...

    java范例开发大全(pdf&源码)

    第13章 多线程编程(教学视频:121分钟) 405 13.1 多线程的五种基本状态 405 实例222 启动线程 405 实例223 参赛者的比赛生活(线程休眠唤醒) 407 实例224 资源搜索并下载(线程等待和通报) 410 实例225 模拟淘宝...

    java范例开发大全源代码

    第1篇 Java编程基础  第1章 Java开发环境的搭建(教学视频:9分钟) 2  1.1 理解Java 2  1.2 搭建Java所需环境 3  1.2.1 下载JDK 3  1.2.2 安装JDK 4  1.2.3 配置环境 5  1.2.4 测试JDK配置...

    java范例开发大全

    第1篇 Java编程基础 第1章 Java开发环境的搭建(教学视频:9分钟) 2 1.1 理解Java 2 1.2 搭建Java所需环境 3 1.2.1 下载JDK 3 1.2.2 安装JDK 4 1.2.3 配置环境 5 ...实例291 BBS论坛服务器端 567 实例292 ...

    Java范例开发大全(全书源程序)

    第13章 多线程编程(教学视频:121分钟) 405 13.1 多线程的五种基本状态 405 实例222 启动线程 405 实例223 参赛者的比赛生活(线程休眠唤醒) 407 实例224 资源搜索并下载(线程等待和通报) 410 实例225 ...

Global site tag (gtag.js) - Google Analytics