java基于TCP协议实现聊天程序

JAVA程序设计之基于TCP协议的socket聊天程序 ,供大家参考,具体内容如下

一、程序实现的功能

1、进入客户端界面
2、创建昵称
3、群发信息
4、@私聊
5、下线通知
6、在线人数统计

二、整体架构图

三、简单介绍

本程序实现了基于TCP通信的聊天程序:

1 服务器端:

服务器端继承JFrame框架,添加组件。创建服务器端的socket,起一个线程池,每接收到一个客户端的连接,分配给其一个线程处理与客户端的通信,将每个客户端的昵称和服务器分配给其的输出流存储到哈希表中。通过检索哈希表中昵称和输出流实现群聊和私聊。

2 客户端:

客户端继承JFrame框架,添加组件。创建客户端的socket,输入昵称,创建客户端socket对应的输入流输出流,与服务器端建立通讯。

四、设计描述

本程序的实现是以服务器端为中继,客户端的所有信息都先发送给服务器端。服务器端辨别是否为私聊信息,私聊信息发送给相应的私聊对象,否则,发送给所有的客户端对象。

(一) 服务器端:

1.1 服务器端继承JFrame框架,添加组件。
1.2 创建服务器端socket。建立一个哈希表,用于存储客户端的昵称以及服务器端对于每个连接的客户端建立的输出流。
1.3建立一个线程池,为每个连接的客户端分配一个执行线程。
1.3调用服务器端Socket的accept()函数,等待客户端的连接,每连接到一个客户端,线程池给相应的客户端分配一个线程。
1.4每个线程内,调用服务器端Socket,封装getOutputStream(),获得服务器端Socket相对应于连接的客户端的输出流和输入流。输入流首先读取到客户端发送来的昵称。将客户端的昵称和服务器端的输出流存储在哈希表中,并遍历整个哈希表,将某人上线的通知发送给所有的在线客户端。
1.5客户端将信息发送给服务器端,当服务器端传来的信息符合“@私聊对象:私聊信息”的格式时,服务器端认为这是私聊信息。服务器端将把私聊对象的昵称从信息中提取出来,通过哈希表找到与昵称对应的输出流。将私聊信息通过输出流发送给私聊对象。
当不是私聊信息时,服务器遍历整个哈希表,通过每个客户端对应的输出流发送给每个客户端。
1.6当客户端下线时,服务器端将移除哈希表中对应存储的客户端昵称以及输出流。并通知在线的每个客户端,某人已下线。

(二) 客户端:

2.1 客户端继承框架JFrame,添加各种组件。
2.2 创建客户端Socket,设置请求连接服务器端IP,以及使用的端口号。
2.3 封装客户端Socket的getInputStream()函数,获得客户端Socket的输入流接受服务器端发来的信息,封装Socket的getOutputStream()函数,获得Socket的输出流向服务器端发送信息。
2.4 通过向文本框添加动作事件监听器,监听文本框的输入。
2.5 当与服务器端连接成功时,系统提醒输入昵称。系统将对输入的昵称进行检索。判断是否有重复的昵称。如有重复则创建不成功,继续输入。
2.6 向服务器端发送信息时,如想对某人发送私聊信息,则需输入符合“@私聊对象的呢称:私聊信息”的格式,此时只有私聊对象和本人可以接收到。否则,发送的信息为公聊信息,所有的客户端都能够收到。
2.7 客户端不断接受服务器端的信息显示在文本域。

五、代码说话

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(), "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);

              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(), "UTF-8"), 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、私聊:

私聊格式“@名称:”+内容。
私聊时,只有私聊的两个人可以接收到信息,其余人接收不到交流信息。
例:马衍硕和李琦琦私聊,小红接收不到私聊信息。
马衍硕和李琦琦接收到了私聊信息:



小红没有接收到私聊信息:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java学习之利用TCP实现的简单聊天示例代码

    TCP TCP协议是面向连接.保证高可靠性(数据无丢失.数据无失序.数据无错误.数据无重复到达)传输层协议. TCP通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯. 本文主要介绍了java利用TCP实现简单聊天的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 示例代码 使用tcp协议实现的简单聊天功能(非常简单的) 思想:使用2个线程,一个线程是用来接收消息的,另一个线程是用来发消息的. 客户端Demo代码: public

  • java编程实现多人聊天室功能

    本文实例为大家分享了java实现多人聊天室的具体代码,供大家参考,具体内容如下 程序源代码及运行截图: server.java //server.java package Socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; impor

  • java实现基于Tcp的socket聊天程序

    对于步入编程行业不深的初学者或是已经有所领会的人来说,当学习一项新的技术的时候,非常渴望有一个附上注释完整的Demo.本人深有体会,网上的例子多到是很多,但是很杂不完整,写代码这种东西来不得半点马虎,要是错了一点,那也是运行不了的.这对于初学者来说更加的头疼,因为他根本不知道错在哪里,盲目的改只能错上加错.最后不得不去找找看看有没有能够直接运行的例子再加以模仿. 下面是博主在学习Java的socket时写的一个完整的例子,并且带上了完整的注释.它是一个简单的聊天程序,但是它可以设置任意多用户同时

  • Java使用TCP套接字实现多人聊天功能详解

    本文实例讲述了Java使用TCP套接字实现多人聊天功能.分享给大家供大家参考,具体如下: 废话不多说,直接开搞: 先创建一个服务端: package interWebWriterEven2; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; /** * 服务端 * @author * */ public class ServiceT { static ArrayList<Socket

  • Java编程实现基于TCP协议的Socket聊天室示例

    本文实例讲述了Java编程实现基于TCP协议的Socket聊天室.分享给大家供大家参考,具体如下: 这里使用Socket套接字进行编程,完成的是基于TCP可靠服务实现服务器与客户端的双通信. Server服务器端: package com.han; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.Win

  • java实现简单TCP聊天程序

    本文实例为大家分享了java实现TCP聊天程序的具体代码,供大家参考,具体内容如下 服务端代码: package com.test.server; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public

  • 基于java编写局域网多人聊天室

    由于需要制作网络计算机网络课程设计,并且不想搞网络布线或者局域网路由器配置等等这种完全搞不懂的东西,最后决定使用socket基于java编写一个局域网聊天室: 关于socket以及网络编程的相关知识详见我另一篇文章:Java基于socket编程 程序基于C/S结构,即客户端服务器模式. 服务器: 默认ip为本机ip 需要双方确定一个端口号 可设置最大连接人数 可启动与关闭 界面显示在线用户人以及姓名(本机不在此显示) 客户端: 需要手动设置服务器ip地址(局域网) 手动设置端口号 输入姓名 可连

  • java socket实现聊天室 java实现多人聊天功能

    用java socket做一个聊天室,实现多人聊天的功能.看了极客学院的视频后跟着敲的.(1DAY) 服务端: 1. 先写服务端的类MyServerSocket,里面放一个监听线程,一启动就好 2. 实现服务端监听类ServerListener.java,用accept来监听,一旦有客户端连上,生成新的socket,就新建个线程实例ChatSocket.启动线程后就把线程交给ChatManager管理 3. 在ChatSocket中实现从客户端读取内容,把读取到的内容发给集合内所有的客户端 4.

  • java实现一个简单TCPSocket聊天室功能分享

    本文实例为大家分享了java实现TCPSocket聊天室功能的相关代码,供大家参考,具体内容如下 1.TCPserver.java import java.net.*; import java.io.*; import java.util.*; import java.util.concurrent.*; public class TCPserver{ private static final int SERVERPORT = 8888; private ServerSocket MyServe

  • Java基于Tcp/ip连接的多人交互聊天室

    本文实例为大家分享了Java  Socket编程实现多人交互聊天室的具体代码,供大家参考,具体内容如下 本项目由三个.java文件(Client.java.Server.java.UI.java)和一个.jpg图片文件组成UI.java是负责界面的构成文件.本聊天室的界面极其简单.主要分为两个界面:第一个是启动时需要登陆的界面如下: 输入名字进去以后就可以直接聊天     这个聊天室相当于群聊,每一个登陆进去的人发的信息,其他人都会收到. 使用指南: 1.运行Server.java文件,保证服务

  • java使用MulticastSocket实现基于广播的多人聊天室

    使用MulticastSocket实现多点广播: (1)DatagramSocket只允许数据报发给指定的目标地址,而MulticastSocket可以将数据报以广播的方式发送到多个客户端. (2)IP协议为多点广播提供了这批特殊的IP地址,这些IP地址的范围是:224.0.0.0至239.255.255.255.. (3)MulticastSocket类时实现多点广播的关键,当MulticastSocket把一个DaragramPocket发送到多点广播的IP地址时,该数据报将会自动广播到加入

随机推荐