-
java Socket 简单的即时聊天 (IM)大数据平台 / dataplatform 2dot5 写在2018年01月16日
我们上面讲了多线程,今天我们用Socket结合多线程实现一个简单IM。
1、服务器代码
package com.test.soctket; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * * IM 服务器 * * @author victor * */ public class IMServer { private int port = 8081; // 默认端口 /** * 默认构造方法 */ public IMServer() { } /** * * @param port * 端口 */ public IMServer(int port) { this.port = port; } /** * 启动服务 * * @throws IOException */ public void start() throws IOException { // TODO:建立用户登陆状态保存类(启动单例模式) Constants state = Constants.getInstance(); // TODO:建立服务器 ServerSocket server = new ServerSocket(port); while (true) { // TODO:等待用户访问 Socket socket = server.accept(); // TODO:用线程处理单独用户请求。 Thread socketThread = new ServerThread(socket); socketThread.start(); } } public static void main(String[] args) throws IOException { // TODO:构建服务器类 IMServer server = new IMServer(8081); server.start(); } }
2、用户状态保存代码 (单例模式)
package com.test.soctket; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * 用户登陆状态保存 * * @author victor * */ public class Constants { public Map<String, Socket> userMap = Collections.synchronizedMap(new HashMap<String, Socket>()); //用户登陆状态保存 public List<String> userList = Collections.synchronizedList(new ArrayList<String>());//用户列表 private static Constants constants = null; private Constants() { } /** * 返回Constants本身,确保Constants只被创建一次 * * @return */ public static Constants getInstance() { if (constants == null) { constants = new Constants(); } return constants; } }
3、处理单独用户请求代码 (多线程,继承Thread类)
package com.test.soctket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; /** * * 处理单独用户请求 * * @author victor * */ public class ServerThread extends Thread { private Socket socket = null; private BufferedReader is = null; private PrintWriter os = null; private String name = ""; private int state = 0; // 第一次链接记录用户名,后面不做操作 public ServerThread(Socket socket) throws IOException { // TODO:获取用户socket并建立输入和输出流 this.socket = socket; this.is = new BufferedReader(new InputStreamReader(socket.getInputStream())); this.os = new PrintWriter(socket.getOutputStream()); } public void run() { try { String readline = is.readLine(); // 用户登陆第一次发过来的用户名 // TODO:如果用户名已存在就断开链接,如果不存在就建立链接 if (Constants.getInstance().userMap.get(readline) == null) { // TODO:接受到close结束通讯 while (!readline.equals("close")) { // TODO: 用户是否第一次登陆 if (state == 1) { // TODO: list 命令 获取有多少在线用户 if (readline.equals("list")) { System.out.println(Constants.getInstance().userList.size()); for (String user : Constants.getInstance().userList) { os.println(user + "\r\n"); os.flush(); } } else { // TODO: 命令协议部分 @用户名+空格+内容部分 // TODO: 内容部分不能有空格 if (readline.indexOf(" ") > -1) { String s[] = readline.split(" "); String username = s[0].substring(s[0].indexOf("@") + 1, s[0].length()); String content = s[1]; // TODO:获取内容要发送给那个用户。 if (Constants.getInstance().userMap.get(username) != null) { // TODO:获取接收用户的输出流,发送信息给对用用户。 PrintWriter print = new PrintWriter( Constants.getInstance().userMap.get(username).getOutputStream()); print.println(content); print.flush(); } } else { os.println("命令协议格式不对"); os.flush(); } } } else { // TODO:用户第一次登陆注册信息 name = readline; Constants.getInstance().userMap.put(name, socket); Constants.getInstance().userList.add(name); state = 1; } System.out.println(readline); readline = is.readLine(); } } else { // TODO: 用户名重复 os.println("用户已存在"); os.flush(); } os.println("close\r\n"); os.flush(); os.close(); // 关闭Socket输出流 is.close(); socket.close(); // 关闭Socket System.out.println("结束会话"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { close(); is = null; socket = null; } } /** * 清楚用户在线信息 */ public void close() { Constants.getInstance().userMap.remove(name); for (int i = 0; i < Constants.getInstance().userList.size(); i++) { String tmp = Constants.getInstance().userList.get(i); if (tmp.equals(name)) { Constants.getInstance().userList.remove(i); } } } }
4、客户端代码
package com.test.soctket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; /** * * IM 客户端 * * @author victor * */ public class IMClient { private String name = "user"; // 登陆用户名 private String ip = "127.0.0.1"; // 登陆服务器ip private int port = 8080; //登陆服务器端口 private Socket socket = null; //socket对象 private BufferedReader is = null; //接收服务器信息输入流 private PrintWriter os = null; // 发送信息的输出流 private BufferedReader cmd = null; //接收命令行输入流 private String input = ""; public IMClient() { } /** * * @param ip 登陆服务器ip * @param port 登陆服务器端口 */ public IMClient(String ip, int port) { this.ip = ip; this.port = port; } /** * * @param ip 登陆服务器ip * @param port 登陆服务器端口 * @param name 登陆用户名 */ public IMClient(String ip, int port, String name) { this.ip = ip; this.port = port; this.name = name; } /** * 启动服务 * * @throws IOException * @throws InterruptedException */ public void start() throws IOException, InterruptedException { // TODO:建立链接 socket = new Socket(ip, port); os = new PrintWriter(socket.getOutputStream()); is = new BufferedReader(new InputStreamReader(socket.getInputStream())); // TODO:启动线程单独处理输入流 ClientRead clientRead = new ClientRead(is); Thread t = new Thread(clientRead); t.start(); // TODO: 协议建立链接第一条发送用户名 os.println(name); os.flush(); // TODO: 用户系统数据信息 while (!input.equals("close")) { cmd = new BufferedReader(new InputStreamReader(System.in)); input = cmd.readLine(); // TODO: 发送用户内容给服务器 os.println(input); os.flush(); } Thread.sleep(100); os.close(); is.close(); socket.close(); } public static void main(String[] args) throws IOException, InterruptedException { // TODO:启动客户端 IMClient client = new IMClient("127.0.0.1", 8081, "user"); client.start(); // IMClient client1 = new IMClient("127.0.0.1", 8081, "user1"); // client.start(); } }
5、客户端信息接收代码 (多线程,继承Runnable接口)
package com.test.soctket; import java.io.BufferedReader; import java.io.IOException; /** * * 客户端接收信息单独处理 * * @author victor * */ public class ClientRead implements Runnable { private BufferedReader in = null; public ClientRead() { } /** * * @param in 服务器输入流 */ public ClientRead(BufferedReader in) { this.in = in; } @Override public void run() { String readline; try { readline = in.readLine(); // TODO:处理服务器发来的信息,close是结束通讯 while (!readline.equals("close")) { System.out.println(readline); readline = in.readLine(); } System.out.println(readline); System.exit(1); //强行停止整个程序 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { } }
Socket是我们熟悉一门语言的最后一步,这步完成我们的java初识就算完结了,后面我会结合一些自己的经验写一些东西,有什么建议欢迎大家给我发邮件 heyucheng_1983@163.com
上一篇: zookeeper安装
下一篇: hadoop 2.0 安装
-
HBase shell 基本命令
我在前面已经分享了hadoop和hbase的安装...
-
zookeeper安装
下载地址: http://zookeeper.apache.or...
-
易观方舟argo安装
一、硬件情况 操作系统:CentOS Linux r...
-
hadoop 2.0 安装
Hadoop2.0 配置SSH 安装 在线安装ssh&nb...
-
Hbase安装
上篇文章我们已经讲了Hadoop的安装, 这...
-
Hadoop安装(Linux环境)
Hadoop俨然已经成为大数据的标准,搭建...
相关推荐
转眼又是新一年,博主万事如意不差钱!
2018年01月22日下午12:20
那个用户状态类中的state怎么使用呀,我这边发送client时总是报错,说是命令格式协议不对
2018年01月27日下午4:23
你发送的信息里没有空格,空格前是用户名,后面内内容比如 @admin nihao
2018年01月30日下午3:36