Java实现TCP一对一通信,实现UDP群聊通信

news/2024/5/18 14:00:47 标签: java, tcp/ip, udp

TCP一对一通信:

实现服务端对话框:

其中可自由更改对话框的样式

java">
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class QqMain extends JFrame implements ActionListener{
    public static void main(String[] args){
 
        InetAddress ia = null;
        try {
            ia = ia.getLocalHost();
            String localip = ia.getHostAddress();
            System.out.println("本机的ip是 :" + localip);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        new QqMain();
    }
 
 
    // 说明:一个类需要页面的显示,则那个类要继承JFrame。
    // 属性
    // 文本域
    private JTextArea jta;
    // 滚动条
    private JScrollPane jsp;
    // 面板里面是文本框和按钮
    private JPanel jp;
    private JTextField jtf;
    private JButton jb ;
 
    BufferedWriter bw  = null;
 
    // 构造器
    public QqMain(){
 
        // 初始化上面的属性
        jta = new JTextArea();
 
        // 将文本域添加到滚动条中
        jsp = new JScrollPane(jta);
        jp = new JPanel();
        jtf =new JTextField(15);
        jb = new JButton("发送");
 
        // 把按钮和文本框添加到面板中
        jp.add(jtf);
        jp.add(jb);
 
        // 把滚动条和面板添加到JFrame中去
        this.add(jsp,BorderLayout.CENTER); //这个设置在中间
        this.add(jp,BorderLayout.SOUTH); //南
 
        this.setTitle("qq聊天");
        this.setSize(500,500);
        this.setLocation(200, 200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
 
        /***********TCP协议*************/
        jb.addActionListener(this);  // 这是按钮点击使用
        // 回车键的监听事件 在接口KeyListener中
        //jtf.addKeyListener(this);
 
 
        jtf.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent e) {
                if((char)e.getKeyChar()==KeyEvent.VK_ENTER) {
                    useVoid();
                }
            }
        });
 
        try{
            // 1.创建一个服务端的套接字
            ServerSocket serverSocket = new ServerSocket(8888);
 
            //2.等待客户端的连接
            Socket socket = serverSocket.accept();
 
            // 3.获取socket通道的输入流(输入流的读取方式为一行一行的读取方式 ----> readLine())
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
 
            // 4.获取通道的输入流(也是一行一行的写出  BufferedWriter ->newLine())
            // 当用户点击“发送”按钮的时候才会,写出数据
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            String line = null;
            while((line = br.readLine()) !=null){
                // 将读取的数据拼接到文本域中显示
                jta.append(line + "\n");
            }
 
 
            // 5.关闭socket通道
            serverSocket.close();
 
        }catch(IOException e){
            e.printStackTrace();
        }
 
        /************************/
 
 
    }
    // 点击按钮所实现的方法
    public void actionPerformed(ActionEvent e){
        useVoid();
    }
 
    public void useVoid(){
        // 1.获取文本框中的内容
        String text = jtf.getText();
        text = "服务端对客户端说:" + text;
        // 自己显示
        jta.append(text + "\n");
        // 2.发送
        try{
            // 4.发送
            bw.write(text);
            bw.newLine(); // 换行
            bw.flush();  // 刷新
            // 5.清空文本框
            jtf.setText("");
        }catch (IOException e1){
            e1.printStackTrace();
        }
    }
 
 
	/*public void KeyPressed(KeyEvent e){
		//回车键
		System.out.println("按钮数字");
	}
	public void KeyTyped(KeyEvent e){
	}
	public void KeyReleased(KeyEvent e){
	}*/
    //行为
}

实现客户端的对话框来获取服务器端的ip地址和端口号进行链接:

java">
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class QqFu extends JFrame implements ActionListener{
    public static void main(String[] args){
        new QqFu();
    }
    // 说明:一个类需要页面的显示,则那个类要继承JFrame。
    // 属性
    // 文本域
    private JTextArea jta;
    // 滚动条
    private JScrollPane jsp;
    // 面板里面是文本框和按钮
    private JPanel jp;
    private JTextField jtf;
    private JButton jb ;
 
    BufferedWriter bw = null;
 
    // 构造器
    public QqFu(){
 
        // 初始化上面的属性
        jta = new JTextArea();
 
        // 将文本域添加到滚动条中
        jsp = new JScrollPane(jta);
        jp = new JPanel();
        jtf =new JTextField(15);
        jb = new JButton("发送");
 
        // 把按钮和文本框添加到面板中
        jp.add(jtf);
        jp.add(jb);
 
        // 把滚动条和面板添加到JFrame中去
        this.add(jsp,BorderLayout.CENTER); //这个设置在中间
        this.add(jp,BorderLayout.SOUTH); //南
 
        this.setTitle("qq聊天客户端");  //获取用户的昵称
        this.setSize(500,500);
        this.setLocation(200, 200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        jb.addActionListener(this);
 
        // 回车点击事件
 
        jtf.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent e) {
                if((char)e.getKeyChar()==KeyEvent.VK_ENTER) {
                    useVoid01();
                }
            }
        });
 
 
 
        try{
            /*******客户端 TCP协议*********/
            // 1.创建一个客户端的套接字(尝试连接)
            Socket socket = new Socket("127.0.0.1",8888);
            // 2.获取socket通道的输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 3
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            String line = null;
            while((line = br.readLine()) !=null){
                jta.append(line + "\n");
            }
            // 3. 获取输出流
 
            // 4.关闭流
            socket.close();
 
            /******************************/
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    public void actionPerformed(ActionEvent e){
        useVoid01();
    }
 
    public void useVoid01(){
        // 1.获取文本框中需要发送的内容
        String text = jtf.getText();
        // 2. 拼接内容
        text = "客户端对服务端说:" + text;
        // 3.自己显示
        jta.append(text + "\n");
        try{
            // 4.发送
            bw.write(text);
            bw.newLine(); // 换行
            bw.flush();  // 刷新
            // 5.清空
            jtf.setText("");
 
        }catch(IOException e1){
            e1.printStackTrace();
        }
    }
    //行为
}

必须先启动服务端再启动客户端才可,如果是两台电脑的情况下,只需要获得其中一个电脑的ip进行服务器启动,另一个进行链接即可。就可实现实时对话

效果展示:

UDP群聊服务器端:

java">
 
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 UDPServer extends JFrame{      
 
    private JTextArea m_display=new JTextArea();
 
    private ServerSocket serverSocket;  
 
    /** 
    * 创建线程池来管理客户端的连接线程 
    * 避免系统资源过度浪费 
    */  
    private ExecutorService exec;  
 
    // 存放客户端之间私聊的信息  
    private Map<String,PrintWriter> storeInfo;  
 
    public UDPServer() {  
        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) {  
        UDPServer server = new UDPServer();
        server.setSize(400,400);
        server.setVisible(true);
        server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        server.start();  
    }  
}  
 

UDP客户端:

java">
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 UDPClient 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 UDPClient() 
    {
        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 {  
        UDPClient client = new UDPClient();
        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、这里是服务器端,显示当前连接人数,以及公聊信息:

自由创建对象来实现群聊

效果如图:


http://www.niftyadmin.cn/n/5246585.html

相关文章

探索Spring事件监听机制的奇妙世界

文章目录 什么是Spring事件监听机制主要组件内置的事件监听类自定义事件监听类总结 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 什么是Spring事件监听机制 Spring事件监听机制是Spr…

何隆昌 docker部署TiDB

docker部署TiDB https://docs.pingcap.com/zh/tidb/stable/quick-start-with-tidb#%E5%9C%A8%E5%8D%95%E6%9C%BA%E4%B8%8A%E6%A8%A1%E6%8B%9F%E9%83%A8%E7%BD%B2%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E9%9B%86%E7%BE%A4 1、下载并安装 TiUP。 curl --proto https --tlsv1.2…

深入了解Java 8日期时间新玩法:DateTimeFormatter与ZoneOffset的使用

推荐语 在这篇文章中&#xff0c;我们将深入探讨Java中的DateTimeFormatter和ZoneOffset类的功能和使用方法。这些类是在Java 8中引入的新的日期时间API的一部分&#xff0c;它们为我们提供了更灵活、更易用的日期和时间处理能力。尽管这些类在Java 8中已经出现&#xff0c;但…

阿里云磁盘在线扩容

我们从阿里云的控制面板中给硬盘扩容后结果发现我们的磁盘空间并没有改变 注意&#xff1a;本次操作是针对CentOS 7的 &#xfeff;#使用df -h并没有发现我们的磁盘空间增加 #使用fdisk -l发现确实还有部分空间 运行df -h命令查看云盘分区大小。 以下示例返回分区&#xf…

远程服务器——如何在Conda中安装R环境

目录 1. R的安装2. VScode 配置参考文献 1. R的安装 推荐使用anaconda或者miniconda&#xff0c;创建虚拟环R_env境然后安装R&#xff1b; 使用conda search r-base查看可下载的R的版本&#xff1b;R版本比较低&#xff0c;一般可以先增加源&#xff1a; % 增加源 conda con…

【Android】查看keystore的公钥和私钥

前言&#xff1a; 查看前准备好.keystore文件&#xff0c;安装并配置openssl、keytool。文件路径中不要有中文。 一、查看keystore的公钥&#xff1a; 1.从keystore中获取MD5证书 keytool -list -v -keystore gamekeyold.keystore 2.导出公钥文件 keytool -export -alias …

MATLAB - 绘制立体图(平面+水深)

目录 代码结果 代码 % 在 X-Y 平面上绘图 % 正常绘制平面图 [X,Y,Z] peaks; contour(X,Y,Z,20); hold on% ****重点******************************************** % 改为三维视图&#xff0c;具体可以help % view(3); %此时的平面图对应z0 &#xff1b;默认az-37.5&#x…

java基础之StringBuffer和StringBuilder

1、概念 当对字符串进行修改的时候&#xff0c;需要使用 StringBuffer 和 StringBuilder 类。 2、与String的区别 String字符串常量一旦声明则不可改变&#xff0c;而字符串对象可以改变&#xff0c;但是改变的是其内存地址的指向。所以String类不适合于频繁修改的字符串操作上…