Socket客户端与服务端通信私聊

来源:互联网 发布:windows 10 pro iso 编辑:程序博客网 时间:2024/05/19 13:25

客户端:

/** * 将聊天室客户端内容独立完成一次. * 下面内容可以选做: * 修改代码,使聊天室可以实现用户自定义昵称, * 以及私聊功能。 *  * 参考思路: * 客户端连接服务端后,要求用户输入一个昵称, * 然后将改昵称发送给服务端,服务端那边读取到 * 客户端发送的第一个字符串认为是昵称。 *  * 私聊功能可以定义格式,例如: * @张三:你好 * 服务端在读取客户端发送过来的昵称时,需要进行 * 解析,分解出昵称与聊天内容,然后将该聊天内容 * 单独发送给指定昵称的用户。 * 服务端的输出流需要使用Map进行维护,而不能再 * 使用List,Map的key可以是该用户昵称,value * 为该用户输出流。 * @author Xiloer * */public class Client {private Socket socket;public Client() throws IOException{socket=new Socket("176.195.107.88",8088);System.out.println("已连接服务器!");}private void inputNickName(Scanner scan) throws  Exception{String nickName = null;//创建输出流PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8"),true);//创建输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));while(true){System.out.println("请创建您的昵称:");nickName = scan.nextLine();if (nickName.trim().equals("")){System.out.println("昵称不得为空");}else {pw.println(nickName);String pass = br.readLine();if(pass!=null&&!pass.equals("OK")){System.out.println("昵称已经被占用,请更换!");break;}else{System.out.println("你好!"+nickName+"可以开始聊天了");break;}}}}public void start(){try {System.out.println("请输入:");Scanner scanner=new Scanner(System.in);inputNickName(scanner);ServerHandler server=new ServerHandler();Thread t=new Thread(server);t.start();OutputStream os = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");PrintWriter pw = new PrintWriter(osw,true);while(true){pw.println(scanner.nextLine());}} catch (Exception e) {e.printStackTrace();}finally{if(socket !=null){try{socket.close();}catch(IOException e){e.printStackTrace();}}}}public static void main(String[] args) throws IOException {Client client=new Client();  client.start();}    private class ServerHandler implements Runnable{public void run() {try {InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is,"UTF-8");BufferedReader br = new BufferedReader(isr);String msgString = null;while((msgString = br.readLine())!= null){System.out.println(msgString);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

服务端:

/** * 将聊天室服务端内容独立完成一次 * 下面内容可以选做: * 配合客户端实现支持昵称与私聊功能 * @author Xiloer * */public class Server {private ServerSocket server;//private List<PrintWriter> allOut;private Map<String,PrintWriter> allOut;public Server(){try {server=new ServerSocket(8088);allOut = new HashMap<String, PrintWriter>();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private void addOut(String key,PrintWriter value){synchronized(this){allOut.put(key, value);}}private synchronized void removeOut(String  key){allOut.remove(key);System.out.println("当前在线人数为:"+ allOut.size());}private synchronized void sendMsgToAll(String message){for(PrintWriter out: allOut.values()){out.println(message);System.out.println("当前在线人数为:"+ allOut.size());}}private synchronized void sendMsgToPrivate(String nickname,String message){PrintWriter pw = allOut.get(nickname); //将对应客户端的聊天信息取出作为私聊内容发送出去if(pw!=null){pw.println(message);System.out.println("1111111111111111111111111111111111111");System.out.println("当前在线私聊人数为:"+ allOut.size());}}public void start(){try{while(true){System.out.println("等待客户端连接.......");Socket socket=server.accept();System.out.println("客户端已连接!");ClientHandler client=new ClientHandler(socket);Thread t=new Thread(client);t.start();}}catch(Exception e){e.printStackTrace();}}public static void main(String[] args) {Server server=new Server();server.start();}private class ClientHandler implements Runnable{    private Socket socket;    private String host;    private String nickName;   public ClientHandler(Socket socket){    this.socket=socket;    InetAddress adress=socket.getInetAddress();    host=adress.getHostAddress();    }    private String getNickName() throws Exception{try{//服务端的输入流读取客户端发送来的昵称输出流InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in,"UTF-8");BufferedReader bReader = new BufferedReader(isr);//服务端将昵称验证结果通过自身的输出流发送给客户端OutputStream out = socket.getOutputStream();OutputStreamWriter iosw = new OutputStreamWriter(out,"UTF-8");PrintWriter ipw = new PrintWriter(iosw,true);//读取客户端发来的昵称String nameString = bReader.readLine();while(true){if(nameString.trim().length()==0){ipw.println("FAIL");}if(allOut.containsKey(nameString)){ipw.println("FAIL");}else {ipw.println("OK");return nameString;}}}catch(Exception e){throw e;}}public void run(){PrintWriter pw = null;try {/** 通过客户端的Socket获取客户端的输出流* 用来将消息发送给客户端*/OutputStream os = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");pw = new PrintWriter(osw,true);/** 将客户昵称和其所说的话作为元素存入共享集合HashMap中*/nickName = getNickName();addOut(nickName, pw);Thread.sleep(100);/** 服务端通知所有客户端,某用户登录*/sendMsgToAll("[系统通知]:欢迎**"+nickName+"**登陆聊天室!");/** 通过客户端的Socket获取输入流* 读取客户端发送来的信息*/InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is,"UTF-8");BufferedReader br = new BufferedReader(isr);String msgString = null;while((msgString = br.readLine())!=null){//验证是否是私聊if(msgString.startsWith("@")){/** 私聊格式:@昵称:内容*/int index = msgString.indexOf(":");if(index >=0){//获取昵称String name = msgString.substring(1,index);String info = msgString.substring(index+1,msgString.length());info = nickName + "对你说:"+ info;//将私聊信息发送出去sendMsgToPrivate(name, info);//服务端不在广播私聊的信息continue;}System.out.println("已输出");}/** 遍历所有输出流,将该客户端发送的信息转发给所有客户端*/System.out.println(nickName+"说:"+ msgString);sendMsgToAll(nickName+"说:"+ msgString);} }catch (Exception e) {/** 因为Win系统用户的客户端断开连接后,br.readLine()方法读取* 不到信息就会抛出异常,而Linux系统会持续发送null;* 因此这里就不在将捕获的异常抛出了。*/}finally{/** 当执行到此处时,说明客户端已经与服务端断开连接* 则将该客户端存在共享集合中的输出流删除*/removeOut(nickName);/** 通知所有客户端,某某客户已经下线*/sendMsgToAll("[系统通知]:"+nickName + "已经下线了。");/** 关闭socket,则通过Socket获取的输入输出流也一同关闭了*/if(socket!=null){try{socket.close();}catch(IOException e){e.printStackTrace();}}}}}    }


原创粉丝点击