本文实例为大家分享了 java socket实现多人 群聊 与 私聊 的具体代码,供大家参考,具体内容如下
关于socket套接字的一些基本知识与认识可以参见 上一篇 或自行查阅。
serversocket和socket实现群聊与私聊涉及到多线程编程,实现过程的重点是利用socket通信的原理,即不断的在服务端和客户端创建输入输出流来相互传递、交换数据等以达到通信的目的。具体实现如下:
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
import java.io.*; import java.net.*; import java.util.hashmap; import java.util.map; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.threadpoolexecutor;
public class tcpserver {
private serversocket serversocket;
/** * 创建线程池来管理客户端的连接线程 * 避免系统资源过度浪费 */ private executorservice exec;
// 存放客户端之间私聊的信息 private map<string,printwriter> storeinfo;
public tcpserver() { try {
serversocket = new serversocket( 6789 ); storeinfo = new hashmap<string, printwriter>(); exec = executors.newcachedthreadpool();
} catch (exception e) { e.printstacktrace(); } }
// 将客户端的信息以map形式存入集合中 private void putin(string key,printwriter value) { synchronized ( this ) { storeinfo.put(key, value); } }
// 将给定的输出流从共享集合中删除 private synchronized void remove(string key) { storeinfo.remove(key); system.out.println( "当前在线人数为:" + storeinfo.size()); }
// 将给定的消息转发给所有客户端 private synchronized void sendtoall(string message) { for (printwriter out: storeinfo.values()) { out.println(message); } }
// 将给定的消息转发给私聊的客户端 private synchronized void sendtosomeone(string name,string message) { printwriter pw = storeinfo.get(name); //将对应客户端的聊天信息取出作为私聊内容发送出去 if (pw != null ) pw.println(message); }
public void start() { try { while ( true ) { system.out.println( "等待客户端连接... ... " ); socket socket = serversocket.accept();
// 获取客户端的ip地址 inetaddress address = socket.getinetaddress(); system.out.println( "客户端:[" + address.gethostaddress() + "]连接成功! " ); /** * 启动一个线程,由线程来处理客户端的请求,这样可以再次监听 * 下一个客户端的连接 */ exec.execute( new listenrclient(socket)); //通过线程池来分配线程 } } catch (exception e) { e.printstacktrace(); } }
/** * 该线程体用来处理给定的某一个客户端的消息,循环接收客户端发送 * 的每一个字符串,并输出到控制台 */ class listenrclient implements runnable {
private socket socket; private string name;
public listenrclient(socket socket) { this .socket = socket; }
// 创建内部类来获取昵称 private string getname() throws exception { try { //服务端的输入流读取客户端发送来的昵称输出流 bufferedreader breader = new bufferedreader( new inputstreamreader(socket.getinputstream(), "utf-8" )); //服务端将昵称验证结果通过自身的输出流发送给客户端 printwriter ipw = new printwriter( new outputstreamwriter(socket.getoutputstream(), "utf-8" ), true );
//读取客户端发来的昵称 while ( true ) { string namestring = breader.readline(); if ((namestring.trim().length() == 0 ) || storeinfo.containskey(namestring)) { ipw.println( "fail" ); } else { ipw.println( "ok" ); return namestring; } } } catch (exception e) { throw e; } }
@override public void run() { try { /* * 通过客户端的socket获取客户端的输出流 * 用来将消息发送给客户端 */ printwriter pw = new printwriter( new outputstreamwriter(socket.getoutputstream(), "utf-8"), true);
/* * 将客户昵称和其所说的内容存入共享集合hashmap中 */ name = getname(); putin(name, pw); thread.sleep(100);
// 服务端通知所有客户端,某用户上线 sendtoall("[系统通知] [" + name + "]已上线");
/* * 通过客户端的socket获取输入流 * 读取客户端发送来的信息 */ bufferedreader breader = new bufferedreader( new inputstreamreader(socket.getinputstream(), "utf-8" )); string msgstring = null ;
while ((msgstring = breader.readline()) != null ) { // 检验是否为私聊(格式:@昵称:内容) if (msgstring.startswith( "@" )) { int index = msgstring.indexof( ":" ); if (index >= 0 ) { //获取昵称 string thename = msgstring.substring( 1 , index); string info = msgstring.substring(index+ 1 , msgstring.length()); info = name + ":" + info; //将私聊信息发送出去 sendtosomeone(thename, info); continue ; } } // 遍历所有输出流,将该客户端发送的信息转发给所有客户端 system.out.println(name+ ":" + msgstring); sendtoall(name+ ":" + msgstring); } } catch (exception e) { // e.printstacktrace(); } finally { remove(name); // 通知所有客户端,某某客户已经下线 sendtoall( "[系统通知] " +name + "已经下线了。" );
if (socket!= null ) { try { socket.close(); } catch (ioexception e) { e.printstacktrace(); } } } } }
public static void main(string[] args) { tcpserver server = new tcpserver(); server.start(); } } |
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
import java.io.*; import java.net.*; import java.util.scanner; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.threadpoolexecutor;
public class tcpclient {
static private socket clientsocket;
public tcpclient() {}
public static void main(string[] args) throws exception { scanner scanner = new scanner(system.in); string serverip;
system.out.println( "请设置服务器ip:" ); serverip = scanner.next(); clientsocket = new socket(serverip, 6789 ); tcpclient client = new tcpclient(); client.start(); }
public void start() { try { scanner scanner = new scanner(system.in); setname(scanner);
// 接收服务器端发送过来的信息的线程启动 executorservice exec = executors.newcachedthreadpool(); exec.execute( new listenrservser());
// 建立输出流,给服务端发信息 printwriter pw = new printwriter( new outputstreamwriter(clientsocket.getoutputstream(), "utf-8" ), true );
while ( true ) { pw.println(scanner.nextline()); } } catch (exception e) { e.printstacktrace(); } finally { if (clientsocket != null ) { try { clientsocket.close(); } catch (ioexception e) { e.printstacktrace(); } } } }
private void setname(scanner scan) throws exception { string name; //创建输出流 printwriter pw = new printwriter( new outputstreamwriter(clientsocket.getoutputstream(), "utf-8" ), true ); //创建输入流 bufferedreader br = new bufferedreader( new inputstreamreader(clientsocket.getinputstream(), "utf-8" ));
while ( true ) { system.out.println( "请创建您的昵称:" ); name = scan.nextline(); if (name.trim().equals( "" )) { system.out.println( "昵称不得为空" ); } else { pw.println(name); string pass = br.readline(); if (pass != null && (!pass.equals( "ok" ))) { system.out.println( "昵称已经被占用,请重新输入:" ); } else { system.out.println( "昵称[" +name+ "]已设置成功,可以开始聊天了" ); break ; } } } }
// 循环读取服务端发送过来的信息并输出到客户端的控制台 class listenrservser implements runnable {
@override public void run() { try { bufferedreader br = new bufferedreader( new inputstreamreader(clientsocket.getinputstream(), "utf-8" )); string msgstring; while ((msgstring = br.readline())!= null ) { system.out.println(msgstring); } } catch (exception e) { e.printstacktrace(); } } }
} |
运行结果:
开始自己的实现也不是很完整,后来也是借鉴别人比较好的思想后完善的,权当分享。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
原文链接:https://blog.csdn.net/zhaokx3/article/details/52513019
查看更多关于java Socket实现多人群聊与私聊功能的详细内容...