利用sorket实现聊天功能-服务端实现
工具包
package loaderman.im.util; public class Constants {
public static final String SERVER_IP = "192.168.0.195";
public static final int SERVER_PORT = ; public static final int CLIENT_SERVER_PORT = ;
public static final int CLIENT_FILE_TRANSPORT_PORT = ;
public static final String REGISTER_FAIL = +"";
}
package loaderman.im.util; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; /**
* 数据库工具类
*
*
*/
public class DButil {
/**
* 连接数据库
*
* @return 数据库连接对象
*/
public static Connection connect() { try { Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/qq?useUnicode=true&characterEncoding=utf-8", "root",
"root");
return conn;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
} /**
* 关闭数据库
*
* @param conn
* 传入数据库连接对象
*/
public static void close(Connection con) {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} }
package loaderman.im.util; import java.text.SimpleDateFormat;
import java.util.Date; public class MyDate {
public static String getDateCN() {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String date = format.format(new Date(System.currentTimeMillis()));
return date;// 2018年10月03日 23:41:31
} public static String getDateEN() {
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1 = format1.format(new Date(System.currentTimeMillis()));
return date1;// 2018-10-03 23:41:31
}
}
传输对象建立
packageloaderman.im.tran; import java.io.Serializable; /**
* 传输的对象,直接通过Socket传输的最大对象
*
* @author xjyt
*/
public class TranObject<T> implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L; private TranObjectType type;// 发送的消息类型 private String fromUser;// 来自哪个用户
private String toUser;// 发往哪个用户 private T object;// 传输的对象 public TranObject(TranObjectType type) {
this.type = type;
} public String getFromUser() {
return fromUser;
} public void setFromUser(String fromUser) {
this.fromUser = fromUser;
} public String getToUser() {
return toUser;
} public void setToUser(String toUser) {
this.toUser = toUser;
} public T getObject() {
return object;
} public void setObject(T object) {
this.object = object;
} public TranObjectType getType() {
return type;
} @Override
public String toString() {
return "TranObject [type=" + type + ", fromUser=" + fromUser
+ ", toUser=" + toUser + ", object=" + object + "]";
}
}
packageloaderman.im.tran; /**
* 传输对象类型
* *
*/
public enum TranObjectType {
REGISTER, // 注册
LOGIN, // 用户登录
LOGOUT, // 用户退出登录
FRIENDLOGIN, // 好友上线
FRIENDLOGOUT, // 好友下线
MESSAGE, // 用户发送消息
UNCONNECTED, // 无法连接
FILE, // 传输文件
REFRESH,//刷新好友列表
OFFLINEMESSAGE//离线消息
}
实体类
package loaderman.im.bean; import java.io.Serializable;
//离线消息实体类
public class OffLineMessage implements Serializable {
private String fromUser;
private String toUser;
private String textMsg;
private int msgType;
private String msgTime; public OffLineMessage() {
} public OffLineMessage(String fromUser, String toUser, String textMsg, int msgType, String msgTime) {
this.fromUser = fromUser;
this.toUser = toUser;
this.textMsg = textMsg;
this.msgType = msgType;
this.msgTime = msgTime;
} public String getFromUser() {
return fromUser;
} public void setFromUser(String fromUser) {
this.fromUser = fromUser;
} public String getToUser() {
return toUser;
} public void setToUser(String toUser) {
this.toUser = toUser;
} public String getTextMsg() {
return textMsg;
} public void setTextMsg(String textMsg) {
this.textMsg = textMsg;
} public int getMsgType() {
return msgType;
} public void setMsgType(int msgType) {
this.msgType = msgType;
}
public String getMsgTime() {
return msgTime;
} public void setMsgTime(String msgTime) {
this.msgTime = msgTime;
}
}
package loaderman.im.bean; import java.io.Serializable; /**
* 文本消息 */
public class TextMessage implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String message; public TextMessage() { } public TextMessage(String message) {
this.message = message;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
}
}
package loaderman.im.bean; import java.io.Serializable; /**
* 用户对象
*
*/
public class User implements Serializable { private String userId;
private String userName; public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} private String userHeadPhoto; private String password;
public String getUserId() {
return userId;
} public void setUserId(String userId) {
this.userId = userId;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getUserHeadPhoto() {
return userHeadPhoto;
} public void setUserHeadPhoto(String userHeadPhoto) {
this.userHeadPhoto = userHeadPhoto;
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", userHeadPhoto='" + userHeadPhoto + '\'' +
", password='" + password + '\'' +
'}';
}
}
数据库建立
packageloaderman.dao; import java.util.ArrayList; import loaderman.im.bean.OffLineMessage;
import loaderman.im.bean.User; public interface UserDao {
//注册成功返回用户id
public String register(User u); public boolean login(User u); public ArrayList<User> refresh(String id); public ArrayList<OffLineMessage> getOffLineMessage(String id); public void logout(String id);
boolean isHasUser(String userId); public boolean saveOffLineMessage(OffLineMessage offLineMessage); }
package loaderman.dao.impl; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.lang.String; import loaderman.im.bean.OffLineMessage;
import loaderman.im.bean.User;
import loaderman.im.util.Constants;
import loaderman.im.util.DButil;
import loaderman.im.util.MyDate;
import loaderman.dao.UserDao; public class UserDaoImpl implements UserDao { @Override
public String register(User u) {
String userID;
Connection con = DButil.connect();
String sql1 = "insert into user(userID,userName,password,userHeadPhoto,time) values(?,?,?,?,?)";
String sql2 = "select userID from user";
UserDao dao = UserDaoFactory.getInstance();
boolean hasUser = dao.isHasUser(u.getUserId());
if (!hasUser) {
try {
PreparedStatement ps = con.prepareStatement(sql1);
ps.setString(1, u.getUserId());
ps.setString(2, u.getUserName());
ps.setString(3, u.getPassword());
ps.setString(4, u.getUserHeadPhoto());
ps.setString(5, MyDate.getDateCN());
int res = ps.executeUpdate();
if (res > 0) {
PreparedStatement ps2 = con.prepareStatement(sql2);
ResultSet rs = ps2.executeQuery();
if (rs.last()) { userID = rs.getString("userID");
createFriendtable(userID);// 注册成功后,创建一个已用户id为表名的表,用于存放好友信息
return userID;
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DButil.close(con);
}
} return Constants.REGISTER_FAIL;
} @Override
public boolean login(User u) {
Connection con = DButil.connect();
String sql = "select * from user where userID=? and password=?";
try {
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, u.getUserId());
ps.setString(2, u.getPassword());
ResultSet rs = ps.executeQuery();
if (rs.first()) { return true;
}
} catch (SQLException e) {
return false;
} finally {
DButil.close(con);
}
return false;
} /**
* 查找自己
*/
public User findMe(String UserId) {
User me = new User();
Connection con = DButil.connect();
String sql = "select * from user where userID=?";
PreparedStatement ps;
try {
ps = con.prepareStatement(sql);
ps.setString(1, UserId);
ResultSet rs = ps.executeQuery();
if (rs.first()) {
me.setUserId(rs.getString("userID"));
me.setUserName(rs.getString("userName"));
me.setUserHeadPhoto(rs.getString("userHeadPhoto")); }
return me;
} catch (SQLException e) {
// e.printStackTrace();
} finally {
DButil.close(con);
}
return null;
} public boolean isHasUser(String userId) {
Connection con = DButil.connect();
String sql = "select * from user where userID=?";
PreparedStatement ps;
try {
ps = con.prepareStatement(sql);
ps.setString(1, userId);
ResultSet rs = ps.executeQuery();
if (rs.first()) {
return true;
} else {
return false;
} } catch (SQLException e) {
// e.printStackTrace();
} finally {
DButil.close(con);
return false;
} }
//保存离线消息
@Override
public boolean saveOffLineMessage(OffLineMessage offLineMessage) {
Connection con = DButil.connect();
String sql = "insert into offlinemessage(fromUser,toUser,textMsg,msgType,msgTime) values(?,?,?,?,?)";
PreparedStatement ps = null;
try {
ps = con.prepareStatement(sql);
ps.setString(1, offLineMessage.getFromUser());
ps.setString(2, offLineMessage.getToUser());
ps.setString(3, offLineMessage.getTextMsg());
ps.setInt(4, offLineMessage.getMsgType());
ps.setString(5, offLineMessage.getMsgTime());
int res = ps.executeUpdate();
if (res > 0) {
return true;
} else {
return false;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false; }
@Override
public ArrayList<OffLineMessage> getOffLineMessage(String toUser) {
ArrayList<OffLineMessage> list = new ArrayList<OffLineMessage>(); Connection con = DButil.connect();
String sql = "select * from offlinemessage where toUser= ?" ;
String sql2 = "delete from offlinemessage where toUser= ?" ; PreparedStatement ps;
try {
ps = con.prepareStatement(sql); ps.setString(1, toUser);
ResultSet rs = ps.executeQuery();
if (rs.first()) {
System.out.println("离线消息获取");
do {
OffLineMessage offLineMessage = new OffLineMessage();
offLineMessage.setFromUser(rs.getString("fromUser"));
offLineMessage.setMsgType(rs.getInt("msgType"));
offLineMessage.setTextMsg(rs.getString("textMsg"));
offLineMessage.setToUser(rs.getString("toUser"));
offLineMessage.setMsgTime(rs.getString("msgTime"));
list.add(offLineMessage);
} while (rs.next());
}
ps = con.prepareStatement(sql2);
ps.setString(1, toUser);
ps.executeUpdate();
return list;
} catch (SQLException e) {
e.printStackTrace();
System.out.println("异常" + e.toString());
} finally {
DButil.close(con);
}
return null; } /**
* 刷新好友列表
*/
@Override
public ArrayList<User> refresh(String userId) {
ArrayList<User> list = new ArrayList<User>();
User me = findMe(userId);
System.out.println("me -- > " + me);
list.add(me);// 先添加自己
Connection con = DButil.connect();
String sql = "select * from " + userId; PreparedStatement ps;
try {
ps = con.prepareStatement(sql);
// ps.setString(1, userId);
ResultSet rs = ps.executeQuery();
if (rs.first()) {
System.out.println("好友消息获取");
do {
User friend = new User();
friend.setUserId(rs.getString("userID"));
friend.setUserName(rs.getString("userName"));
friend.setUserHeadPhoto(rs.getString("userHeadPhoto"));
list.add(friend);
} while (rs.next());
}
return list;
} catch (SQLException e) {
e.printStackTrace();
System.out.println("异常" + e.toString());
} finally {
DButil.close(con);
}
return null;
} /**
* 注册成功后,创建一个用户表,保存该用户好友
*
* @param userID
*/
public void createFriendtable(String userID) {
Connection con = DButil.connect();
try {
String sql = "create table _" + userID
+ " (id int auto_increment not null primary key,"
+ " userID varchar(20) not null,"
+ " userName varchar(20) not null,"
+ "userHeadPhoto varchar(50) )";
PreparedStatement ps = con.prepareStatement(sql);
int res = ps.executeUpdate();
System.out.println(res);
} catch (SQLException e) {
e.printStackTrace();
} finally {
DButil.close(con);
}
} /**
* 下线更新状态为离线
*/
@Override
public void logout(String userID) {
Connection con = DButil.connect();
try {
String sql = "update user set _isOnline=0 where userID=?";
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, userID);
ps.executeUpdate();
// updateAllOff(userID);
// System.out.println(res);
} catch (SQLException e) {
// e.printStackTrace();
} finally {
DButil.close(con);
}
} public List<String> getAllId() {
Connection con = DButil.connect();
List<String> list = new ArrayList<String>();
try {
String sql = "select _id from user";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if (rs.first()) {
do {
String id = rs.getString("_id");
list.add(id);
} while (rs.next());
}
// System.out.println(list);
return list;
} catch (SQLException e) {
// e.printStackTrace();
} finally {
DButil.close(con);
}
return null;
} public static void main(String[] args) {
// User u = new User();
UserDaoImpl dao = new UserDaoImpl();
ArrayList<OffLineMessage> test = dao.getOffLineMessage("test");
System.out.println(test.size());
//
//
// System.out.println(list); } }
package loaderman.dao.impl; import petrochina.xjyt.fcydyy.dao.UserDao; public class UserDaoFactory {
private static UserDao dao; public static UserDao getInstance() {
if (dao == null) {
dao = new UserDaoImpl();
}
return dao;
}
}
服务器实现
package loaderman.server; import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List; import loaderman.im.bean.OffLineMessage;
import loaderman.im.tran.TranObjectType;
import loaderman.dao.UserDao;
import loaderman.im.bean.TextMessage;
import loaderman.im.bean.User;
import loaderman.im.tran.TranObject;
import loaderman.im.util.MyDate;
import loaderman.dao.impl.UserDaoFactory; /**
* 读消息线程和处理方法
*
*/
public class InputThread extends Thread {
private Socket socket;// socket对象
private OutputThread out;// 传递进来的写消息线程,因为我们要给用户回复消息啊
private OutputThreadMap map;// 写消息线程缓存器
private ObjectInputStream ois;// 对象输入流
private boolean isStart = true;// 是否循环读消息 public InputThread(Socket socket, OutputThread out, OutputThreadMap map) {
this.socket = socket;
this.out = out;
this.map = map;
try {
ois = new ObjectInputStream(socket.getInputStream());// 实例化对象输入流
} catch (IOException e) {
e.printStackTrace();
}
} public void setStart(boolean isStart) {// 提供接口给外部关闭读消息线程
this.isStart = isStart;
} @Override
public void run() {
try {
while (isStart) {
// 读取消息 System.out.println("InputThread读消息开始");
readMessage();
System.out.println("InputThread读消息完成"); }
if (ois != null)
ois.close();
if (socket != null)
socket.close();
} catch (ClassNotFoundException e) {
System.out.println("异常信息1");
isStart = false;// 结束自己的读循环
e.printStackTrace();
} catch (SocketException e){
System.out.println("InputThread1"+e.toString()); }catch (IOException e) {
System.out.println("InputThread2"+e.toString());
isStart = false;// 结束自己的读循环
e.printStackTrace();
}catch (Exception e){
System.out.println("InputThread3"+e.toString());
e.printStackTrace();
}
} /**
* 读消息以及处理消息,抛出异常
*
* @throws IOException
* @throws ClassNotFoundException
*/
public void readMessage() throws IOException, ClassNotFoundException {
System.out.println("readMessage 1 "); Object readObject = ois.readObject();// 从流中读取对象
System.out.println("readMessage 2 ");
UserDao dao = UserDaoFactory.getInstance();// 通过dao模式管理后台
if (readObject != null && readObject instanceof TranObject) {
TranObject read_tranObject = (TranObject) readObject;// 转换成传输对象
switch (read_tranObject.getType()) {
case REGISTER:// 如果用户是注册
System.out.println("REGISTER");
User registerUser = (User) read_tranObject.getObject(); String registerResult = dao.register(registerUser);
System.out.println(MyDate.getDateCN() + " 新用户注册:"
+ registerResult);
// 给用户回复消息
TranObject<User> register2TranObject = new TranObject<User>(
TranObjectType.REGISTER);
User register2user = new User();
register2user.setUserId(registerResult);
register2TranObject.setObject(register2user);
out.setMessage(register2TranObject);
break;
case LOGIN:
System.out.println("LOGIN"); User loginUser = (User) read_tranObject.getObject(); System.out.println("登录用户 " + loginUser.toString());
boolean login = dao.login(loginUser);
TranObject<Boolean> login2Object = new TranObject<Boolean>(
TranObjectType.LOGIN);
User login2User = new User();
login2User.setUserId(loginUser.getUserId()); if (login) {// 如果登录成功
System.out.println("登录成功");
TranObject<User> onObject = new TranObject<User>(
TranObjectType.LOGIN); onObject.setObject(login2User);
for (OutputThread onOut : map.getAll()) {
onOut.setMessage(onObject);// 广播一下用户上线
} map.add(loginUser.getUserId(), out);// 先广播,再把对应用户id的写线程存入map中,以便转发消息时调用 login2Object.setObject(true);// 把好友列表加入回复的对象中
System.out.println(MyDate.getDateCN() + " 用户:" + loginUser.getUserId() + " 上线了"); } else {
login2Object.setObject(false);// 把好友列表加入回复的对象中
}
out.setMessage(login2Object);// 同时把登录信息回复给用户 System.out.println(MyDate.getDateCN() + " 用户:"
+ loginUser.getUserId() + " 上线了");
break;
case LOGOUT:// 如果是退出,更新数据库在线状态,同时群发告诉所有在线用户
System.out.println("LOGOUT"); User logoutUser = (User) read_tranObject.getObject();
String offId = logoutUser.getUserId();
System.out
.println(MyDate.getDateCN() + " 用户:" + offId + " 下线了");
dao.logout(offId);
isStart = false;// 结束自己的读循环
map.remove(offId);// 从缓存的线程中移除
out.setMessage(null);// 先要设置一个空消息去唤醒写线程
out.setStart(false);// 再结束写线程循环 TranObject<User> offObject = new TranObject<User>(
TranObjectType.LOGOUT);
User logout2User = new User();
logout2User.setUserId(logoutUser.getUserId());
offObject.setObject(logout2User);
for (OutputThread offOut : map.getAll()) {// 广播用户下线消息
offOut.setMessage(offObject);
}
break;
case MESSAGE:// 如果是转发消息(可添加群发)
System.out.println("MESSAGE"); // 获取消息中要转发的对象id,然后获取缓存的该对象的写线程
String id2 = read_tranObject.getToUser(); System.out.println("给谁发" + id2);
OutputThread toOut = map.getById(id2);
if (toOut != null) {// 如果用户在线
System.out.println("用户在线");
TextMessage tm = (TextMessage) read_tranObject.getObject();
System.out.println("消息内容 " + tm.getMessage());
toOut.setMessage(read_tranObject); } else {// 如果为空,说明用户已经下线,回复用户
TextMessage text = new TextMessage();
System.out.println("用户不在线"); TranObject<TextMessage> offText = new TranObject<TextMessage>(
TranObjectType.MESSAGE);
offText.setObject(text);
offText.setFromUser(id2);
String fromUser = read_tranObject.getFromUser();
String toUser = read_tranObject.getToUser();
TextMessage tm = (TextMessage) read_tranObject.getObject();
//保存离线消息
OffLineMessage offLineMessage = new OffLineMessage(fromUser, toUser, tm.getMessage(), 0, MyDate.getDateEN());
boolean saveOffLineMessage = dao.saveOffLineMessage(offLineMessage);
if (saveOffLineMessage) {
text.setMessage("亲!对方不在线哦,您的消息将暂时保存在服务器");
} else {
text.setMessage("亲!无法发送,请稍后重试");
}
out.setMessage(offText);
}
break;
case REFRESH:
System.out.println("REFRESH");
System.out.println("当前用户REFRESH" + read_tranObject
.getFromUser()); List<User> refreshList = dao.refresh(read_tranObject.getFromUser());
System.out.println(refreshList.size());
TranObject<List<User>> refreshO = new TranObject<List<User>>(
TranObjectType.REFRESH);
refreshO.setObject(refreshList);
out.setMessage(refreshO);
break; case OFFLINEMESSAGE: System.out.println("客户端要获取离线消息了"); ArrayList<OffLineMessage> offLineMessage = dao.getOffLineMessage(read_tranObject.getFromUser()); TranObject<List<OffLineMessage>> offMsgObject = new TranObject<List<OffLineMessage>>(
TranObjectType.OFFLINEMESSAGE); offMsgObject.setObject(offLineMessage);
offMsgObject.setFromUser(read_tranObject.getFromUser()); out.setMessage(offMsgObject); break; default:
break;
}
} }
/**
* 判断是否断开连接,连接返回true,断开返回false
* @return
*/
public Boolean isServerConnetion( Socket socket){ try{
socket.sendUrgentData(0xFF);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
return true;
}catch(Exception se){ return false;
}
}
}
package loaderman.server; import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException; import loaderman.im.tran.TranObject; /**
* 写消息线程
*
*/
public class OutputThread extends Thread {
private OutputThreadMap map;
private ObjectOutputStream oos;
private TranObject object;
private boolean isStart = true;// 循环标志位
private Socket socket; public OutputThread(Socket socket, OutputThreadMap map) {
try {
this.socket = socket;
this.map = map;
oos = new ObjectOutputStream(socket.getOutputStream());// 在构造器里面实例化对象输出流
} catch (IOException e) {
e.printStackTrace();
}
} public Socket getSocket() {
return socket;
} public void setStart(boolean isStart) {
this.isStart = isStart;
} // 调用写消息线程,设置了消息之后,唤醒run方法,可以节约资源
public void setMessage(TranObject object) {
this.object = object;
synchronized (this) {
System.out.println("OutputThread唤醒");
notify();
}
} @Override
public void run() {
try {
while (isStart) { if (object != null) {
System.out.println("OutputThread写出开始");
oos.writeObject(object);
System.out.println("OutputThread写出中");
oos.flush();
System.out.println("OutputThread写出结束");
}
// 没有消息写出的时候,线程等待
synchronized (this) {
System.out.println("OutputThread等待");
wait();
} }
if (oos != null){// 循环结束后,关闭流,释放资源
oos.close();
}
if (socket != null) {
socket.close();
} } catch (InterruptedException e) {
System.out.println("OutputThread1" + e.toString()); e.printStackTrace();
} catch (SocketException e) {
System.out.println("OutputThread2" + e.toString()); } catch (IOException e) {
System.out.println("OutputThread3" + e.toString());
e.printStackTrace();
}
}
}
package loaderman.server; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* 存放写线程的缓存器 */
public class OutputThreadMap {
private HashMap<String, OutputThread> map;
private static OutputThreadMap instance; // 私有构造器,防止被外面实例化改对像
private OutputThreadMap() {
map = new HashMap<String, OutputThread>();
} // 单例模式像外面提供该对象
public synchronized static OutputThreadMap getInstance() {
if (instance == null) {
instance = new OutputThreadMap();
}
return instance;
} // 添加写线程的方法
public synchronized void add(String id, OutputThread out) {
OutputThread outputThread = map.get(id);
System.out.println(id + "之前线程 --> " + outputThread);
System.out.println(id + "新线程 --> " + out); if (outputThread!=null){
outputThread.setMessage(null);
outputThread.setStart(false);
}
map.put(id, out);
OutputThread outputThread2 = map.get(id);
System.out.println(id + "现在运行新线程 --> " + outputThread2);
} // 移除写线程的方法
public synchronized void remove(String id) {
map.remove(id); } // 取出写线程的方法,群聊的话,可以遍历取出对应写线程
public synchronized OutputThread getById(String id) {
return map.get(id);
} // 得到所有写线程方法,用于向所有在线用户发送广播
public synchronized List<OutputThread> getAll() {
List<OutputThread> list = new ArrayList<OutputThread>();
for (Map.Entry<String, OutputThread> entry : map.entrySet()) {
list.add(entry.getValue());
}
return list;
}
}
package loaderman.server; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import loaderman.im.util.Constants;
import loaderman.im.util.MyDate; /**
* 服务器,接受用户登录、离线、转发消息
* */
public class Server {
private ExecutorService executorService;// 线程池
private ServerSocket serverSocket = null;
private Socket socket = null;
private boolean isStarted = true; public Server() {
try {
// 创建线程池,池中具有(cpu个数*50)条线程
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors() * 50);
serverSocket = new ServerSocket(Constants.SERVER_PORT);
} catch (IOException e) {
e.printStackTrace();
quit();
}
} public void start() {
try {
while (isStarted) {
System.out.println(MyDate.getDateCN() + " 服务器已启动...");
socket = serverSocket.accept(); System.out.println("客户端已经连接");
String ip = socket.getInetAddress().toString();
System.out.println(MyDate.getDateCN() + " 用户:" + ip + " 已建立连接");
// 为支持多用户并发访问,采用线程池管理每一个用户的连接请求
if (socket.isConnected())
executorService.execute(new SocketTask(socket));// 添加到线程池
}
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 in;
private OutputThread out;
private OutputThreadMap map; public SocketTask(Socket socket) {
this.socket = socket;
map = OutputThreadMap.getInstance();
} @Override
public void run() {
out = new OutputThread(socket, map);//
// 先实例化写消息线程,(把对应用户的写线程存入map缓存器中)
in = new InputThread(socket, out, map);// 再实例化读消息线程
out.setStart(true);
in.setStart(true);
in.start();
out.start();
}
} /**
* 退出
*/
public void quit() {
System.out.println("退出"); try {
this.isStarted = false;
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
new Server().start(); }
}
完成
利用sorket实现聊天功能-服务端实现的更多相关文章
- Socket聊天程序——服务端
写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...
- 如何利用cURL和python对服务端和web端进行接口测试
工具描述 cURL是利用URL语法在命令行方式下工作的文件传输工具,是开源爱好者编写维护的免费工具,支持包括Windows.Linux.Mac等数十个操作系统,最新版本为7.27.0,但是我推荐大家使 ...
- 利用WebSocket和EventSource实现服务端推送
可能有很多的同学有用 setInterval 控制 ajax 不断向服务端请求最新数据的经历(轮询)看下面的代码: setInterval(function() { $.get('/get/data- ...
- winform客户端利用webClient实现与Web服务端的数据传输
由于项目需要,最近研究了下WebClient的数据传输.关于WebClient介绍网上有很多详细介绍,大概就是利用WebClient可以实现对Internet资源的访问.无外乎客户端发送请求,服务端处 ...
- 利用控制台承载SignalR作为服务端、及第三方推送信息
一 首先建立一个控制台需要引用一些组件 特别要注意引用Microsoft.Owin.Host.HttpListener别忘了这个组件,不引用他可能程序正常运行不会报错,但服务器一直开启失败(我之前就是 ...
- 利用IDEA创建Web Service服务端和客户端的详细过程
创建服务端 一.file–>new–>project 二.点击next后输入服务端名,点击finish,生成目录如下 三.在 HelloWorld.Java 文件中右击,选 WebServ ...
- go实现多聊天并发 服务端
package main import ( "fmt" "net" "time")type Client struct { ch chan ...
- Netty 实现 WebSocket 聊天功能
上一次我们用Netty快速实现了一个 Java 聊天程序(见http://www.waylau.com/netty-chat/).现在,我们要做下修改,加入 WebSocket 的支持,使它可以在浏览 ...
- 手写内网穿透服务端客户端(NAT穿透)原理及实现
Hello,I'm Shendi. 这天心血来潮,决定做一个内网穿透的软件. 用过花生壳等软件的就知道内网穿透是个啥,干嘛用的了. 我们如果有服务器(比如tomcat),实际上我们在电脑上开启了服务器 ...
随机推荐
- python数据写入Excel表格
from openpyxl import Workbook def main(): sheet_name = "表名1" row_count = 6 # 行数 info_resul ...
- pytorch训练模型的一些坑
1. 图像读取 opencv的python和c++读取的图像结果不一致,是因为python和c++采用的opencv版本不一样,从而使用的解码库不同,导致读取的结果不同. 详细内容参考:https:/ ...
- MySQL数据库的二进制安装、源码编译和基础入门操作
一.MySQL安装 (1)安装方式: 1 .程序包yum安装 优点:安装快,简单 缺点:定死了各个文件的地方,需要修改里边的相关配置文件,很麻烦 2 .二进制格式的程序包:展开至特定路径,并经过简单配 ...
- Introduction of Machine Learning
李宏毅主页 台湾大学语音处理实验室 人工智慧.机器学习与深度学习间有什么区别? 人工智能——目标 机器学习——手段 深度学习——机器学习的一种方法 人类设定好的天生本能 Machine Learnin ...
- Road to Cinema(贪心+二分)
https://www.cnblogs.com/flipped/p/6083973.html 原博客转载 http://codeforces.com/group/1EzrFFyOc0/co ...
- tensorflow几个常见错误
错误一:二分类,标签y ValueError: Cannot feed value of shape (128,1) for Tensor u'input_y_2:0', which has shap ...
- Java数组直接选择排序、sort()排序
/** * 1.数组sort()排序 * 2.直接选择排序(两重for循环排序) */ import java.lang.*; import java.lang.reflect.Array; impo ...
- MongoDB C#samus驱动
MongoDB的c#驱动有两种,官方驱动和samus驱动,不过我更喜欢samus驱动,因为samus驱动提供了丰富的linq操作. 官方驱动:https://github.com/mongodb/mo ...
- springBoot maven项目打成jar包
springBoot项目打包springBoot项目打包最常用且最简单的方式是用springBoot的打包plugin <plugin> <groupId>org.spring ...
- swoole组件----mysql查询,插入数据
注意!任何swoole函数都应该包含在go(function(){}) 经典查询方法query() go(function (){ $swoole_mysql = new Swoole\Corouti ...