java socket编程实现群聊(超详细)
Posted 乘凉者 栽树人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java socket编程实现群聊(超详细)相关的知识,希望对你有一定的参考价值。
Java socket编程实现群聊
最终效果
文末有完整代码,创作不易,点个赞再走吧~
- 客户端之间的交流
- 有人退出群聊时,减少在线人数
实现流程
1、项目结构即原理分析
- 功能
- 实现多客户之间聊天
- 实时统计在线人数
- 图形化界面
- 创建昵称
- 下线通知
- 项目结构
- 原理
- 服务端:
创建socket,每次接受一个客户端来连接,就分配一个线程处理和客户端通信,将昵称和服务器分配给其的输出流存储,然后实现群聊 - 客户端
客户端继承JFrame框架,添加组件。创建客户端的socket,输入昵称,创建客户端socket对应的输入流和输出流
2、代码分析
2.1、客户端图形化界面设计
public class ClientFrame
public void frame()
JFrame frame = new JFrame();
frame.setTitle("客户端");
ClientPanel panel = new ClientPanel();
panel.panel();
//panel添加到窗体里面
frame.add(panel);
//布局置空,设置绝对定位
frame.setLayout(null);
frame.setBounds(100, 100, 900, 500);
//设置窗口不可变
frame.setResizable(true);
//设置窗口可见
frame.setVisible(true);
//设置背景颜色
// frame.getContentPane().setBackground(Color.MAGENTA);
//关闭窗体
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
2.2、客户端面板模块
public void panel()
setBounds(30, 30, 800, 410);
// setBackground(LIGHT_GRAY);
setFocusable(true);//设置获取焦点
setLayout(null);//布局自定义
/*lab_ip*/
JLabel lab_ip = new JLabel("IP:");
lab_ip.setBounds(10, 10, 50, 30);
lab_ip.setFont(new Font("宋体", Font.BOLD, 20));//字体样式
lab_ip.setForeground(black);//标签字体前景色
/*ip框*/
JTextField ip = new JTextField(20);
ip.setBounds(60, 10, 180, 30);
ip.setFont(new Font("微软雅黑", Font.BOLD, 20));
/*端口*/
JLabel lab_port = new JLabel("端口:");
lab_port.setBounds(240, 10, 80, 30);
lab_port.setFont(new Font("宋体", Font.BOLD, 20));//字体样式
lab_port.setForeground(black);//标签字体前景色
//用户名称
JLabel username = new JLabel("用户名:");
username.setBounds(450, 10, 80, 30);
username.setFont(new Font("宋体", Font.BOLD, 20));//字体样式
username.setForeground(black);//标签字体前景色
//用户名框
JTextField usernameport = new JTextField(10);
usernameport.setBounds(550, 10, 100, 30);
usernameport.setFont(new Font("微软雅黑", Font.BOLD, 20));
/*端口框*/
JTextField port = new JTextField(10);
port.setBounds(320, 10, 100, 30);
port.setFont(new Font("微软雅黑", Font.BOLD, 20));
/*连接按钮*/
JButton connection = new JButton("连接");
connection.setBounds(700, 10, 100, 30);
connection.setBackground(green);
/*状态标签*/
JLabel flag = new JLabel("");
flag.setBounds(230, 30, 100, 35);
/*接收框*/
TextArea textRec = new TextArea("");
textRec.setBounds(90, 70, 600, 180);
textRec.setFont(new Font("微软雅黑", Font.PLAIN, 20));
/*输入框*/
TextArea textSend = new TextArea(1, 10);
textSend.setColumns(20);
textSend.setBounds(90, 260, 600, 70);
textSend.setFont(new Font("微软雅黑", Font.BOLD, 20));
textSend.setBackground(white);
/*发送按钮*/
JButton btn_en = new JButton("发送");
btn_en.setBounds(440, 350, 100, 40);
btn_en.setBackground(pink);
/*在线人数lab*/
JLabel jLabel = new JLabel("在线人数:");
jLabel.setBounds(0, 70, 90, 35);
jLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
/*人数*/
JLabel online = new JLabel("");
online.setBounds(30, 120, 100, 18);
online.setFont(new Font("微软雅黑", Font.PLAIN, 18));
online.setText("");
add(lab_ip);
add(ip);
add(lab_port);
add(username);
add(usernameport);
add(port);
add(connection);
add(flag);
add(textRec);
add(textSend);
add(btn_en);
2.3、服务端的转发信息方法
//接收消息
public String receiveTest(Socket socket) throws IOException
inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
return new String(bytes, 0, len);
//转发其他客户端方法
public void sendOther(Socket socket, String msg) throws IOException
for (Socket client : ServerTest.list)
if (client == socket)
//2.是自己返回带标记的消息
outputStream = socket.getOutputStream();
InetAddress localAddress = socket.getLocalAddress();
//是自己的返回消息类型
outputStream.write(("len" + msg +"\\r\\n\\n").getBytes());
//客户端是自己不转发
continue;
//输出对应客户端socket
outputStream = client.getOutputStream();
SocketAddress socketAddress = client.getLocalSocketAddress();
//分割字符串,从第一个开始
outputStream.write(( msg+"\\r\\n\\n").getBytes());
System.out.println("已转发=>" + msg);
2.4、服务器统计在线人数
//统计在线人数
public void onLine()
int num = ServerTest.list.size();
List<Socket> sockets = ServerTest.list;
for (Socket client : sockets)
try
outputStream = client.getOutputStream();
outputStream.write(("\\n 【当前在线人数:" + num + "】\\n").getBytes());
catch (IOException e)
e.printStackTrace();
2.5、启动服务器供多客户连接
public class ServerTest
//客户端集合
protected static List<Socket> list = new ArrayList<>();
public static void main(String[] args)
Service service = null;
try
int i = 0;
ServerSocket serverSocket = new ServerSocket(8848);
while (true)
//一直接受客户端请求,多客户端连接
Socket socket = serverSocket.accept();
list.add(socket);
//服务线程
service = new Service(socket);
//开启线程
new Thread(service).start();
service.onLine();
System.out.println("socket=" + socket);
System.out.println("主线程循环" + i++ + "次");
System.out.println("客户端在线数:" + list.size());
catch (IOException e)
e.printStackTrace();
service.onLine();//出异常再次调用通知人数方法
2.6、写一个ip地址和端口号供客户端连接
public static void main(String[] args)
try
ClientBase clientBase = new ClientBase("127.0.0.1",8848);
clientBase.sendTest("hello world","hello world");
System.out.println(clientBase.receiveTest());
catch (IOException e)
e.printStackTrace();
2.7、发送以及接收方法
/**
* 发送方法
*/
public void sendTest(String username ,String msg) throws IOException
//获取 字节输出流
if (msg.length() != 0)
outputStream = socket.getOutputStream();
String sum =username+"说: "+msg;
outputStream.write(sum.getBytes("UTF-8"));
/**
* 接收方法
*
* @return 接收内容
*/
public String receiveTest() throws IOException
//获取服务器回应消息
inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
try
string = new String(bytes, 0, len, "UTF-8");
catch (IOException e)
System.out.println("error");
return string;
2.8、接收到统计的在线人数
/*接收在线人数*/
public String onLine()
String str = "";
InputStream inputStream = null;
try
inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
str = new String(bytes, 0, len);
catch (IOException e)
e.printStackTrace();
try
inputStream.close();
catch (IOException ioException)
ioException.printStackTrace();
return str;
2.9、回到面板写入监听事件
//连接事件监听
connection.addActionListener(new ActionListener()
@Override
public void actionPerformed(ActionEvent e)
try
clientBase = new ClientBase(ip.getText(), Integer.parseInt(port.getText()));
catch (IOException ioException)
flag.setText("未连接");
flag.setForeground(red);
Socket socket = clientBase.getSocket();
if (flag.getText().equals("已连接") && clientBase != null)
else if (socket != null)
try
flag.setText("已连接");
flag.setForeground(green);
//接收线程
new Thread(new Runnable()
private boolean f = true;//线程标志位
@Override
public void run()
//接收消息
while (f)
try
String text = clientBase.receiveTest();
//判断转回的消息是不是自己的
String temp = text.substring(0, 3);//截取前三位字符,注意不包括3 [0,3)
//是否以len开始
if (text.startsWith("len"))
// textRec.setForeground(blue);
//追加收到内容
textRec.append(text.substring(3));//截取第三个到末尾的字符串
else
textRec.setForeground(black);
textRec.append(text);
catch (IOException ioException)
flag.setText("连接重置");
flag以上是关于java socket编程实现群聊(超详细)的主要内容,如果未能解决你的问题,请参考以下文章