java之socket服务框架

我们知道socket通信是分服务端和客户端两种,如何设计一个好的通信框架呢。本文从实战角度构建一个适合中小型项目开发的socket服务框架。

这里需要具有一定的java基础,比如线程知识,socket通信基础。

1.服务端设计与实现


这里我们将服务器端与客户端通信模型为per-connection per-thread,即一个连接一个线程。不过我们这里进行了部分优化,即建立线程池来管理

这些服务线程。

1)服务配置文件

public class Consts {
//服务ip
public static final String ServerIP="127.0.0.1";
//服务端口
public static final int ServerPort=10254;
}

2)socket处理工具类

public class SocketUtil {
    //发送数据
      public static  void Send(String obj,Socket socket) throws Exception{
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
				socket.getOutputStream(), "UTF-8"));
		writer.append(obj);
		writer.newLine();
		writer.flush();
	}
//接受数据
public static String Accept(Socket socket) throws IOException{
	BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
	String line = reader.readLine();
	return line;
}
}


3)服务类

package Server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import utils.logging.Logger;
/*
 * 单例设计模式设计服务类,将服务类设计为线程
 * */
public class Listener extends Thread {

	private static Listener mListener = null;

	public static Listener getInstance() {
		if (mListener == null) {
			synchronized (Listener.class) {
				if (mListener == null)
					mListener = new Listener();
			}
		}

		return mListener;
	}

	// 线程池,用于支持并发。
	private ExecutorService mThreadPool;

	// 关闭标志
	private volatile boolean mStopFlag;

	private ServerSocket mServerSocket;

	/**
	 * 只能存在单实例
	 */
	private Listener() {
		mThreadPool = Executors.newCachedThreadPool();
		mStopFlag = false;
		mServerSocket = null;
	}

	/**
	 * stop
	 */
	public void setStopFlag() {
		mStopFlag = true;
	}

	@Override
	public void run() {
		try {
			mServerSocket = new ServerSocket(Consts.ServerPort);
		} catch (IOException e1) {
			e1.printStackTrace();
			return;
		}

		Logger.getLogger().log("服务器已经启动,等待连接");
		while (!mStopFlag) {
			try {
				Socket socket = null;

				socket = mServerSocket.accept();// which is connected to the
												// socket from client
				// break;
				if (!mStopFlag) {
					mThreadPool.execute(new ClientAcceptor(socket));
				} else {
					socket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		System.out.println("已经跳出循环了");
		try {
			mThreadPool.shutdown();
			mThreadPool.awaitTermination(30, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Logger.getLogger().log("Listener准备退出");
		return;

	}
}

3) socket处理类,即处理连接的线程类

public class ClientAcceptor implements Runnable {
	private Socket mSocket = null;

	public ClientAcceptor(Socket socket) {
		this.mSocket = socket;
	}

	@Override
	public void run() {
		try {
			String resp= readSocket();
			writeResponse("服务器返回....");
		} catch (Exception e) {
		} finally {
			if (!mSocket.isClosed())
				try {
					mSocket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}

	private String readSocket() {
		User user=null;
		if (null == mSocket)
			return "";
		String server_content="";
		try {
			 server_content=SocketUtil.Accept(mSocket);
			System.out.println("接收客户端数据为:"+server_content);
			}
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return server_content;
	}
	private void writeResponse(String resp)
			throws Exception {
		SocketUtil.Send(resp,mSocket);
	}
}

2.客户端设计与实现

public class Client {
	public static Socket socket =null;
	public static void openSocket(){
		try {
			socket=new Socket(Consts.ServerIp, Consts.ServerPort);
		} catch (Exception e) {
			System.out.println("客户端未连接...");
		} 
	}
	public static void close(){
		try {
			socket.close();
		} catch (IOException e) {
		System.out.println("客户端关闭异常...");
		}
	}
public static void main(String []args) throws Exception{
	Listener.getInstance().start();
	System.out.println("客户端等待10秒");
    #为了使服务进程先启动....
    Thread.sleep(1000*10);
    openSocket();
    SocketUtil.Send("hello world",socket);
    System.out.println("------------waitting for response------------------");
    String respstr=SocketUtil.Accept(socket);
    System.out.println(respstr);
    close();
}

上面测试中,我们把服务和客户都放在了main函数里便于操作。结果如下:

客户端等待10秒
2017-03-20 01:43:19 : 服务器已经启动,等待连接
2017-03-20 01:43:29 : 接收到指令,Listener被唤醒
------------waitting for response------------------
接收客户端数据为:hello world
服务器返回....

3.总结

这里我们针对每个连接,我们都创建了一个线程。在访问量很大时,这样的设计方案将会使得服务器的内存被迅速占用。最终会影响体验。下一博客中,我们讨论使用基于事件机制和观察者设计模式来改进设计方案。



  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值