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

2023-12-14 14:29:15

TCP一对一通信:

实现服务端对话框:

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


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地址和端口号进行链接:


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群聊服务器端:


 
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客户端:


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、这里是服务器端,显示当前连接人数,以及公聊信息:

自由创建对象来实现群聊

效果如图:

文章来源:https://blog.csdn.net/qq_74846159/article/details/134869342
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。