基于Java Socket通信实现聊天室功能

目录

1、socket简介

2、架构图

3、服务器端详细过程

4、客户端详细过程

5、完整代码


1、socket简介

        socket 翻译为“套接字”,是计算机之间基于tcp协议的一种连接。两台存在socket连接的计算机可以发送/接收数据。在java中Socket有以下方法:

  1. socket.connect()用于远程连接服务器
  2. socket.setSoTimeout()用于设置超时时间       
  3. socket.getOutputStream()用于写入数据,发送信息
  4. socket.getInputStream()用于读取数据
  5. socket.getRemoteSocketAddress()获取连接地址、端口
  6. socket.bind()为socket关联一个相应地址属性

2、架构图

 3、服务器端详细过程

(1)服务器端启动一个ServerSocket占用并监视7000端口,无限循环调用accept方法来与客户端建立socket连接,每一个socket连接使用一个线程管理。每次创建一个线程,都需要将线程加入到list集合中。

        ServerSocket serverSocket=new ServerSocket(7000);
        System.out.println("服务器已启动!");
        while (true){
            Socket socket=serverSocket.accept();
            System.out.println(String.format("客户端连接已经创建,客户端地址:"+socket.getRemoteSocketAddress()));
            Handler talkThread=new Handler(socket);
            list.add(talkThread);  //加入线程数组中去
            talkThread.start();
        }

(2)服务器端对消息的处理:编写一个工具类Handler处理消息

static class Handler extends Thread{
        Socket socket;
        public Handler(Socket socket){
            this.socket=socket;
        }
}

(3)Handler类继承Thread类,重写run方法。

        @Override
        public void run() {
            try {
                InputStream is=this.socket.getInputStream();
                OutputStream os=this.socket.getOutputStream();
                handle(is,os);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                removeSocket(list);//线程执行完毕,移除集合
            }
            System.out.println(socket.getRemoteSocketAddress()+"客户端连接已断开");
        }

(4)获取socket中的数据/发送数据

            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
            BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream(),StandardCharsets.UTF_8));

(5)在Handler方法中定义一个handle方法,用于处理数据通信

        private void handle(InputStream inputStream,OutputStream outputStream) throws IOException {
            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
            BufferedReader br=new BufferedReader(new InputStreamReader(inputStream,StandardCharsets.UTF_8));
            bw.write("连接成功\n");
            bw.flush();
            while (true){
                String message=br.readLine();  //读取客户端发送过来的消息
                System.out.println(String.format("客户%s:%s",socket.getRemoteSocketAddress(),message));
                sendTalk(list,message);  //发送信息给所有客户端
                if (message.equals("end")){ //用户结束通话,线程执行完毕
                    System.out.println(socket.getRemoteSocketAddress()+"退出");
                    br.close();
                    bw.close();
                    break;
                }
            }
        }

(5)聊天过程中服务器接收到一个客户端发送的数据之后需要将信息发送给所有的客户,我们这里需要遍历一遍线程数组list。调用sendTalk方法,由于是多个客户端,这里涉及到线程并发安全问题,可以使用synchronized 关键字修饰sendTalk方法。

        public synchronized void sendTalk(List<Handler> list,String tellInfo) throws IOException {   //将信息全发送给所有socket连接
            for (Handler v:list){
                PrintWriter printStream=new PrintWriter(v.socket.getOutputStream(),true);
                printStream.println(v.socket.getRemoteSocketAddress()+":"+tellInfo);
            }
        }

线程执行完毕需要移出线程数组list,仍然需要synchronized关键字修饰

        public void removeSocket(List<Handler> list){   //移除socket连接
            synchronized (list){  //使用synchronized关键字修饰list
                list.remove(this);//this 表示当前实例对象,指当前线程
            }
        }

4、客户端详细过程

(1)创建Socket对象连接服务器端

        Socket socket=new Socket("localhost",7000);

(2)编写ClientHandler工具类,用于接收和发送消息

class ClientHandler{
    Socket socket=null;
    boolean flag=true;

    public ClientHandler(Socket socket) {//构造方法
        this.socket = socket;
    }

(3)工具类中包含两个线程,sendMessage和getMessage,一个用于发送信息,一个接收信息

    Thread sendMessage=new Thread(new Runnable() {
        @SneakyThrows
        @Override
        public void run() {
            Scanner scanner=new Scanner(System.in);
            PrintWriter printWriter=new PrintWriter(socket.getOutputStream(),true);
            while (flag){
                String message=scanner.nextLine();
                if(message.equals("")) continue;//发送内容为空,则不发送
                printWriter.println(message);
                if (message.equals("end")||message==null) {
                    flag=false;//如果发送内容为end,则表示结束通信
                    break;
                }
            }
        }
    });
    Thread getMessage=new Thread(new Runnable() {
        @SneakyThrows
        @Override
        public void run() {
            BufferedReader socketReader=new BufferedReader(new InputStreamReader(socket.getInputStream(),StandardCharsets.UTF_8));
            while (flag){
                String sr=socketReader.readLine();
                System.out.println(sr);
            }
        }
    });

5、完整代码

(1)服务器端

package com.example.kunpneg01.controller;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class SocketTest {
    private static List<Handler> list=new ArrayList<>();

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=new ServerSocket(7000);
        System.out.println("服务器已启动!");
        while (true){
            Socket socket=serverSocket.accept();
            System.out.println(String.format("客户端连接已经创建,客户端地址:"+socket.getRemoteSocketAddress()));
            Handler talkThread=new Handler(socket);
            list.add(talkThread);
            talkThread.start();
        }
    }

    static class Handler extends Thread{
        Socket socket;
        public Handler(Socket socket){
            this.socket=socket;
        }
        public synchronized void sendTalk(List<Handler> list,String tellInfo) throws IOException {   //将信息全发送给所有socket连接
            for (Handler v:list){
                PrintWriter printStream=new PrintWriter(v.socket.getOutputStream(),true);
                printStream.println(v.socket.getRemoteSocketAddress()+":"+tellInfo);
            }
        }
        public synchronized void removeSocket(List<Handler> list){   //移除socket连接
            synchronized (list){//
                list.remove(this);
            }
        }

        @Override
        public void run() {
            try {
                InputStream is=this.socket.getInputStream();
                OutputStream os=this.socket.getOutputStream();
                handle(is,os);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                removeSocket(list);//线程执行完毕,移除集合
            }
            System.out.println(socket.getRemoteSocketAddress()+"客户端连接已断开");
        }

        private void handle(InputStream inputStream,OutputStream outputStream) throws IOException {
            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
            BufferedReader br=new BufferedReader(new InputStreamReader(inputStream,StandardCharsets.UTF_8));
            bw.write("连接成功\n");
            bw.flush();
            while (true){
                String message=br.readLine();  //读取客户端发送过来的消息
                System.out.println(String.format("客户%s:%s",socket.getRemoteSocketAddress(),message));
                sendTalk(list,message);
                if (message.equals("end")){ //用户结束通话,线程执行完毕
                    System.out.println(socket.getRemoteSocketAddress()+"退出");
                    br.close();
                    bw.close();
                    break;
                }
            }
        }
    }

}

(2)客户端

package com.example.retry.domain;

import lombok.SneakyThrows;
import org.apache.hadoop.hbase.client.Scan;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class ClientTest {
    public static void main(String[] args) throws IOException {
        Socket socket=new Socket("localhost",7000);
        ClientHandler clientHandler=new ClientHandler(socket);
        clientHandler.start();
    }
}
class ClientHandler{
    Socket socket=null;
    boolean flag=true;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }
    Thread sendMessage=new Thread(new Runnable() {
        @SneakyThrows
        @Override
        public void run() {
            Scanner scanner=new Scanner(System.in);
            PrintWriter printWriter=new PrintWriter(socket.getOutputStream(),true);
            while (flag){
                String message=scanner.nextLine();
                if(message.equals("")) continue;//发送内容为空,则不发送
                printWriter.println(message);
                if (message.equals("end")||message==null) {
                    flag=false;//如果发送内容为end,则表示结束通信
                    break;
                }
            }
        }
    });
    Thread getMessage=new Thread(new Runnable() {
        @SneakyThrows
        @Override
        public void run() {
            BufferedReader socketReader=new BufferedReader(new InputStreamReader(socket.getInputStream(),StandardCharsets.UTF_8));
            while (flag){
                String sr=socketReader.readLine();
                System.out.println(sr);
            }
        }
    });
    public void start(){
        sendMessage.start();
        getMessage.start();
    }
}

  • 11
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Java中可以利用Socket实现一个简单的聊天室。首先需要创建一个服务器端和多个客户端。服务器端负责接收客户端的连接请求,并负责转发客户端发送的消息给其他客户端。客户端则负责连接服务器,并发送和接收消息。 服务器端的实现需要创建一个ServerSocket来监听客户端的连接请求,在接收到客户端连接请求时,创建一个新的线程来处理每个客户端的消息。服务器端接收到客户端的消息后,需要遍历所有的客户端连接,并将消息发送给每个客户端。 客户端的实现需要创建一个Socket来连接服务器端,然后通过输入输出流来发送和接收消息。客户端需要不断地监听服务器端的消息,并将接收到的消息显示在界面上。同时客户端也需要不断地监测用户输入,并将用户输入的消息发送给服务器端。 在实现聊天室时,需要考虑到多个客户端之间的通信以及消息的发送和接收。可以使用线程来处理不同客户端的消息,并使用集合来保存所有连接的客户端。同时还需要考虑到消息的格式和编码方式,确保消息的正确传输和显示。 总之,通过JavaSocket编程,可以实现一个简单的多客户端聊天室。这需要对Socket编程有一定的了解,并且需要考虑到多线程、消息传输等问题。通过合理的设计和实现,可以让多个用户在同一个聊天室实现实时的消息交流。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会写骚年的代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值