以前上Java课的时候,老师要求,自行组队来做一个即时网络通信的课程设计。具体要求:使用Socket套接字和ServerSocket来开发一个基于c/s架构的小项目,服务器和客户端的UI采用Swing编程,具体业务逻辑采用多线程开发。现在过去这么久了,想去回忆一下,记录一下当时的点滴,作为一点点积累。我正在努力回忆..

我主要负责,服务器的设计开发,下面是我的部分代码。

一,UI部分是模仿别人写的,可自行设计。

二,业务部分(多线程处理)

1.线程管理类

View Code

package com.haoyudian.server.service;import java.io.IOException;
import java.net.Inet4Address;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import com.haoyudian.common.util.Constants;
import com.haoyudian.common.util.DateHelper;/*** 服务器管理类 接受用户登录、离线、转发消息* * @author Scherrer* */
public class ServerManager {private ExecutorService executorService;// 线程池private ServerSocket serverSocket = null;private Socket socket;private Boolean isStart = true;public ServerManager() {try {// 创建线程池,池中具有(cpu个数*50)条线程executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);serverSocket = new ServerSocket(Constants.SERVER_PORT);System.out.println("服务器IP="+ Inet4Address.getLocalHost().getHostAddress());} catch (Exception e) {e.printStackTrace();exit();}}/*** 退出方法*/private void exit() {try {this.isStart = false;serverSocket.close();} catch (IOException e) {e.printStackTrace();}}public void start() {System.out.println(DateHelper.getDateByCN() + " 服务器已启动...");try {while(isStart) {socket = serverSocket.accept();String ip =  socket.getRemoteSocketAddress().toString();System.out.println(DateHelper.getDateByCN()+ " 用户:" + ip + " 已建立连接");// 为支持多用户并发访问,采用线程池管理每一个用户的连接请求if (socket.isConnected()) {executorService.execute(new SocketTask(socket));// 添加到线程池
                }}} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null)socket.close();if (serverSocket != null)serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}private final class SocketTask implements Runnable  {private Socket socket = null;private InputThread inThread;private OutputThread outThread;private OutputThreadMap threadMap;public SocketTask(Socket socket) {this.socket = socket;threadMap = OutputThreadMap.getInstance();}@Overridepublic void run() {outThread = new OutputThread(socket);//// 先实例化写消息线程,(把对应用户的写线程存入map缓存器中)inThread = new InputThread(socket, outThread, threadMap);// 再实例化读消息线程outThread.setStart(true);inThread.setStart(true);inThread.start();outThread.start();}}public static void main(String[] args) {new ServerManager().start();}
}

2.发送消息的线程

View Code

package com.haoyudian.server.service;import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;import com.haoyudian.common.bean.trans.TransObject;/*** 发送消息的线程* * @author Scherrer**/
public class OutputThread extends Thread{private ObjectOutputStream oos;//对象输出流private TransObject<?> object;//传输对象private boolean isStart = true;//循环标志private Socket socket;//套接字//private OutputThreadMap outMap;//发送现场缓存对象public OutputThread(Socket s) {try {this.socket = s;//构造器里实例化对象输出流oos = new ObjectOutputStream(this.socket.getOutputStream());} catch (IOException e) {e.printStackTrace();}}/***  调用写消息线程,设置了消息之后,唤醒run方法,可以节约资源* @param object*/public void setMessage(TransObject<?> object) {this.object = object;synchronized(this) {notify();}}public void setStart(boolean isStart) {this.isStart = isStart;}@Overridepublic void run() {try {while(isStart) {//没有消息写的时候,线程等待synchronized (this) {wait();}if (object != null) {oos.writeObject(object);oos.flush();}}} catch (Exception e) {e.printStackTrace();} finally {try {if (oos != null) {oos.close();}if (socket != null) {socket.close();}} catch (IOException e) {// TODO Auto-generated catch block
                e.printStackTrace();}}}}

3.接受消息的线程

View Code

package com.haoyudian.server.service;import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.List;import com.haoyudian.common.bean.TextMessage;
import com.haoyudian.common.bean.User;
import com.haoyudian.common.bean.trans.TransObject;
import com.haoyudian.common.bean.trans.TransObjectType;
import com.haoyudian.common.util.DateHelper;
import com.haoyudian.server.dao.UserDao;
import com.haoyudian.server.dao.UserDaoFactory;public class InputThread extends Thread{private ObjectInputStream ois;//对象读入流private Socket socket;//socket对象private OutputThread outThread;//把接收的消息发送给用户private OutputThreadMap map;//写消息的缓存器private boolean isStart = true;public InputThread(Socket socket,OutputThread out,OutputThreadMap map) {try {this.socket = socket;this.outThread = out;this.map = map;this.ois = new ObjectInputStream(socket.getInputStream());} catch (Exception e) {e.printStackTrace();}}public void setStart(boolean isStart) {// 提供接口给外部关闭读消息线程this.isStart = isStart;}@Overridepublic void run() {try {while(isStart) {//读消息try {readMessage();} catch (Exception e) {//e.printStackTrace();break;}}} catch (Exception e) {e.printStackTrace();} finally {try {if (ois != null) {ois.close();}if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}}private void readMessage() throws IOException, ClassNotFoundException {Object readObj = ois.readObject();//读取消息对象UserDao dao = UserDaoFactory.getInstance();// 通过dao模式管理后台if (readObj != null && readObj instanceof TransObject) {TransObject<?> transObj = (TransObject<?>) readObj;//转换成传输对象switch (transObj.getType()) {case REGISTER://注册User user = (User) transObj.getObject();int regAccout = dao.register(user);System.out.println(DateHelper.getDateByCN() +"新用户注册: " + regAccout);//回复用户TransObject<User> regResult = new TransObject<User>(TransObjectType.REGISTER);User u = new User();u.setAccount(regAccout);regResult.setObject(u);System.out.println("验证一下账号: " + u.getAccount());outThread.setMessage(regResult);break;case LOGIN:User loginUser = (User) transObj.getObject();List<User> list = dao.login(loginUser);System.out.println("好友列表: " + list.size());//返回 listTransObject<List<User>> msg = new TransObject<>(TransObjectType.LOGIN);if (list != null ) {//登陆成功TransObject<User> userOnlineMsg = new TransObject<User>(TransObjectType.LOGIN);//此处 new 一个User ,只广播用户账号,如果用loginUser,则可能泄露密码User tempUser = new User();tempUser.setAccount(loginUser.getAccount());//tempUser.setNickname(nickname)//考虑广播昵称
                    userOnlineMsg.setObject(tempUser);for(OutputThread out : map.getAll()) {//拿到所有用户的发送线程
                        out.setMessage(userOnlineMsg);}//记录当前用户的发送线程
                    map.add(loginUser.getAccount(), outThread);//设置消息
                    msg.setObject(list);} //发送
                outThread.setMessage(msg);System.out.println(DateHelper.getDateByCN() + " 用户:"+ loginUser.getAccount() + " 上线了");break;case MESSAGE:// 如果是转发消息(可添加群发)// 获取消息中要转发的对象id,然后获取缓存的该对象的写线程int toAccount = transObj.getToUser().getAccount();//获取账号OutputThread ot = map.getById(toAccount);//获取发送线程if (ot != null) {ot.setMessage(transObj);//把接收到的消息对象直接发送给另一个用户} else {//用户的缓存发送线程为空,表示表示用户已下线,回复用户TextMessage text = new TextMessage();text.setTextMessage("对方离线,您的消息暂时保存在服务器");TransObject<TextMessage> msgTip = new TransObject<>(TransObjectType.MESSAGE);msgTip.setObject(text);User tempU = new User();tempU.setAccount(0);msgTip.setFromUser(tempU);outThread.setMessage(msgTip);}break;case LOGOUT://下线处理// 如果是退出,更新数据库在线状态,同时群发告诉所有在线用户User logoutUser = (User) transObj.getObject();System.out.println(DateHelper.getDateByCN() + "用户: " + logoutUser.getNickname() + "下线了哈");dao.logout(logoutUser);//结束自己的读消息的线程isStart = false;//移除自己的缓存线程
                map.remove(logoutUser.getAccount());outThread.setMessage(null);// 先要设置一个空消息去唤醒写线程outThread.setStart(false);// 再结束写线程循环
                TransObject<User> offObject = new TransObject<User>(TransObjectType.LOGOUT);User logout2User = new User();logout2User.setAccount(logoutUser.getAccount());offObject.setObject(logout2User);for (OutputThread offOut : map.getAll()) {// 广播用户下线消息
                    offOut.setMessage(offObject);}break;case Refresh_FRIEND_LIST://更新好友List<User> refreshList = dao.refreshFriendList(transObj.getFromUser().getAccount());TransObject<List<User>> refreshMsg = new TransObject<>(TransObjectType.Refresh_FRIEND_LIST);refreshMsg.setObject(refreshList);outThread.setMessage(refreshMsg);break;}}}}

其中,线程池那部分的使用,我觉得很有用,我要特别留意一下

View Code

    public ServerManager() {try {// 创建线程池,池中具有(cpu个数*50)条线程executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);serverSocket = new ServerSocket(Constants.SERVER_PORT);System.out.println("服务器IP="+ Inet4Address.getLocalHost().getHostAddress());} catch (Exception e) {e.printStackTrace();exit();}}try {while(isStart) {socket = serverSocket.accept();String ip =  socket.getRemoteSocketAddress().toString();System.out.println(DateHelper.getDateByCN()+ " 用户:" + ip + " 已建立连接");// 为支持多用户并发访问,采用线程池管理每一个用户的连接请求if (socket.isConnected()) {executorService.execute(new SocketTask(socket));// 添加到线程池
                }}} 

转载于:https://www.cnblogs.com/scherrer/archive/2013/03/02/2940317.html

JAVA 即时网络通信我的服务器相关推荐

  1. tcp网络通信教程 java_基于java TCP网络通信的实例详解

    JAVA中设计网络编程模式的主要有TCP和UDP两种,TCP是属于即时通信,UDP是通过数据包来进行通信,UDP当中就会牵扯到数据的解析和传送.在安全性能方面,TCP要略胜一筹,通信过程中不容易出现数 ...

  2. Java即时编译:不仅仅是一个流行词

    最近的Java生产性能问题迫使我重新审视并真正欣赏Java VM即时(JIT)编译器. 大多数Java开发人员和支持人员都听说过这种JVM运行时性能优化,但是有多少人真正理解并欣赏它的好处? 本文将与 ...

  3. java http服务端例子_简单的用 Java Socket 编写的 HTTP 服务器应用

    /*** SimpleHttpServer.java*/importjava.io.*;importjava.net.*;importjava.util.StringTokenizer;/*** 一个 ...

  4. java 直播服务器_MyLive--使用JAVA实现的直播RTMP服务器

    MyLive 使用JAVA实现的直播RTMP服务器 介绍 MyLive 是一个我用业余时间使用Java实现的RTMP直播服务器,它并不是一个全功能的RTMP实现,也就是说不支持seek和play2命令 ...

  5. 用JAVA SOCKET编程,读服务器几个字符,再写入本地显示

    Server: package cn.itcast.framework.socket;import java.io.BufferedReader; import java.io.IOException ...

  6. Java Web项目在Linux服务器自动化部署续-整合Bamboo

    前言 Java Web项目在Linux服务器自动化部署 在这一篇中, 完成的是一个自动化部署的脚本. Atlassian Bamboo 是一款持续集成构建服务器软件(Build Server) 软件地 ...

  7. JAVA实现简单的FTP服务器

    JAVA实现简单的ftp服务器 通过界面可启动FTP服务,先看看看效果,然后具体代码附后. 点击启动FTP服务后,可以看到控制台: 可以通过get和send以及dir执行相对应的操作. 点击退出按钮, ...

  8. Java web项目如何在服务器上跑起来(有源码)

    Java web项目如何在服务器上跑起来(有源码) 要用到的工具有:myeclipse.宝塔,navicat premium.xshell. 概述:本博文主要是帮助入门级新手怎么从网上下载一个java ...

  9. Java项目部署到云服务器的思路

    Java项目部署到云服务器的思路 1 部署项目的前提条件 1.1 购买云服务器 我购买的是腾讯云的服务器,第一年享优惠88一年 cpu好像两核的,作为入门级的也算够用了 如果第二年该续费的时候,我记得 ...

最新文章

  1. 【关注】3000多警力围剿“毒村”!现实比影视剧更惊险
  2. Windows下怎样设置jar包开机自启动运行
  3. GeosparkViz 可视化
  4. ios 导航栏(自己定义和使用系统方式)
  5. 【转载】浅谈React编程思想
  6. ASP.NET MVC如何使用Ajax的辅助方法
  7. 以太坊2.0合约质押新增4.23万ETH
  8. 评分9.7! 这本Python神作,火爆编程圈!网友:太香!
  9. mysql 分库分表 ~ ShardingSphere生态圈
  10. 如何查询linux服务器的网卡,linux怎么查看网卡硬件信息
  11. 【JAVA】初识Java
  12. unity中移动的九种方法
  13. Spring Boot电商项目53:订单模块二:【前台:创建订单】接口;(这个接口比较复杂,内容较多)
  14. 女孩的问题,男孩的回答
  15. 20140124孤独者之旅23
  16. Scala基础语法1
  17. 基本题型记录-二叉树中序遍历
  18. 2023元旦倒计时代码
  19. Linux迁移home目录到根目录的操作步骤
  20. 2018~2019学年第一学期期末考试试卷(A)卷《C语言程序设计》

热门文章

  1. Web前端JavaScript笔记(3)对象
  2. C++学习笔记(14) static_cast 与 dynamic_cast
  3. udp文件服务器,UDP客户端服务器文件传输
  4. shell中的文本处理(grep、sed、awk命令)
  5. 订单生产计划表范本_服装生产管理必看丨一文解决车间管理混乱
  6. eclipse lombok插件安装_Eclipse导入spring-boot-plus(三)
  7. Unitest框架的使用(三)TestSkip和TestSuite方法
  8. 基础层区块链Harmony发布主网新版本v4.0.0
  9. ChaiNext:ETH底部试探后反弹,测试1500关口
  10. IoTeX与BigQuery集成以使数据对谷歌云用户可用