java基于TCP协议实现聊天程序
JAVA程序设计之基于TCP协议的socket聊天程序 ,供大家参考,具体内容如下 一、程序实现的功能 1、进入客户端界面 二、整体架构图 三、简单介绍 本程序实现了基于TCP通信的聊天程序: 1 服务器端: 服务器端继承JFrame框架,添加组件。创建服务器端的socket,起一个线程池,每接收到一个客户端的连接,分配给其一个线程处理与客户端的通信,将每个客户端的昵称和服务器分配给其的输出流存储到哈希表中。通过检索哈希表中昵称和输出流实现群聊和私聊。 2 客户端: 客户端继承JFrame框架,添加组件。创建客户端的socket,输入昵称,创建客户端socket对应的输入流输出流,与服务器端建立通讯。 四、设计描述 本程序的实现是以服务器端为中继,客户端的所有信息都先发送给服务器端。服务器端辨别是否为私聊信息,私聊信息发送给相应的私聊对象,否则,发送给所有的客户端对象。 (一) 服务器端: 1.1 服务器端继承JFrame框架,添加组件。 (二) 客户端: 2.1 客户端继承框架JFrame,添加各种组件。 五、代码说话 1、服务器端: package server; 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; import javax.swing.*; import java.awt.*; public class TCPServer extends JFrame{ private JTextArea m_display=new JTextArea(); private ServerSocket serverSocket; /** * 创建线程池来管理客户端的连接线程 * 避免系统资源过度浪费 */ private ExecutorService exec; // 存放客户端之间私聊的信息 private Map<String,PrintWriter> storeInfo; public TCPServer() { super("聊天程序服务器端"); Container c=getContentPane(); c.add(new JScrollPane(m_display),BorderLayout.CENTER); try { serverSocket = new ServerSocket(6666); 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); m_display.append("当前在线人数为:"+ storeInfo.size()); //for(String name: storeInfo.key) } // 将给定的消息转发给所有客户端 private synchronized void sendToAll(String message) { for(PrintWriter out: storeInfo.values()) { out.println(message); // m_display.append("已经发送了"); } } // 将给定的消息转发给私聊的客户端 private synchronized void sendToSomeone(String name,String message) { PrintWriter pw = storeInfo.get(name); //将对应客户端的聊天信息取出作为私聊内容发送出去 if(pw != null) pw.println("私聊: "+message); } public void start() { try { m_display.setVisible(true); //m_display.append("mayanshuo"); while(true) { m_display.append("等待客户端连接... ... n"); Socket socket = serverSocket.accept(); // 获取客户端的ip地址 InetAddress address = socket.getInetAddress(); m_display.append("客户端:“" + 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(),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); sendToSomeone(name,info); continue; } } // 遍历所有输出流,将该客户端发送的信息转发给所有客户端 m_display.append(name+":"+ msgString+"n"); sendToAll(name+":"+ msgString); } } catch (Exception e) { // e.printStackTrace(); } finally { remove(name); // 通知所有客户端,某某客户已经下线 sendToAll("*系统消息* "+name + "已经下线了。n"); if(socket!=null) { try { socket.close(); } catch(IOException e) { e.printStackTrace(); } } } } } public static void main(String[] args) { TCPServer server = new TCPServer(); server.setSize(400,400); server.setVisible(true); server.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE); server.start(); } } 2、客户端: package server; 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; import javax.swing.*; import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class TCPClient extends JFrame { private JTextField m_enter=new JTextField(); private JTextArea m_display=new JTextArea(); private int m_count=0; private static Socket clientSocket; //private ExecutorService exec = Executors.newCachedThreadPool(); private BufferedReader br; private PrintWriter pw; public TCPClient() { super("聊天程序客户端"); Container c=getContentPane(); //m_enter.setSize(100,99); //m_display.setSize(200,100); m_enter.setVisible(true); m_display.setVisible(true); m_enter.requestFocusInWindow(); //转移输入焦点到输入区域 //将光标放置在文本区域的尾部 m_display.setCaretPosition(m_display.getText().length()); c.add(m_enter,BorderLayout.SOUTH); c.add(new JScrollPane(m_display),BorderLayout.CENTER); // this.add(panel); // this.setContentPane(jp); } public static void main(String[] args) throws Exception { TCPClient client = new TCPClient(); client.setVisible(true); client.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE); client.setSize(470,708); client.start(); } public void start() { try { m_display.append("请创建用户名:"); clientSocket=new Socket("localhost",6666); BufferedReader br = new BufferedReader( new InputStreamReader(clientSocket.getInputStream(),"UTF-8")); PrintWriter pw = new PrintWriter( new OutputStreamWriter(clientSocket.getOutputStream(),true); //ListenrServser l=new ListenrServser(); m_enter.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event) { try{ String s=event.getActionCommand(); m_enter.setText(""); if(m_count==0) { pw.println(s); m_display.append("n'"+s+"'"+"昵称设置成功。n"); } else { pw.println(s); } m_count++; }catch(Exception e) { e.printStackTrace(); } } }); String msgString; while((msgString = br.readLine())!= null) { m_display.append(msgString+"n"); } } catch(Exception e) { e.printStackTrace(); } finally { if (clientSocket !=null) { try { clientSocket.close(); } catch(IOException e) { e.printStackTrace(); } } } } } 六、运行结果 1、这里是服务器端,显示当前连接人数,以及公聊信息: 2、此时为群内成员公聊: 这里创建了三个角色:马衍硕、李琦琦、小红。 3、私聊: 私聊格式“@名称:”+内容。 小红没有接收到私聊信息: 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 您可能感兴趣的文章:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |