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以上是关于java socket编程实现群聊(超详细)的主要内容,如果未能解决你的问题,请参考以下文章