关于java多用户在线聊天程序的问题。。

时间:2022-08-29 11:27:02
以下是服务端代码

import java.net.*;
import java.net.*;
import java.io.*;
public class Server{
private final int maxClientCount = 10;
private int clientNum = 0;
private ServerSocket ss;
private ChatThread communicationThread[];
public Server(){
//创建ServerSocket,允许10人在线
try{
ss = new ServerSocket(10000,maxClientCount);
}
catch(IOException e){
System.err.println(e.toString());
System.exit(1);
}

communicationThread = new ChatThread[maxClientCount];
//循环等待用户连接
for(int i=0;i<maxClientCount;i++){
try{
communicationThread[i] = new ChatThread(ss.accept(),i);    //连接成功时启动它
communicationThread[i].start();
clientNum++;
}
catch(IOException e){
System.err.println(e.toString());
System.exit(1);
}
}
}
//线程类
private class ChatThread extends Thread{   
private Socket socket;
private int clientID;
private DataInputStream br;
private DataOutputStream bw;
public ChatThread(Socket socket,int number){
this.socket = socket;
clientID = number;
try{
//从socket获得输入流和输出流
br = new DataInputStream(socket.getInputStream());
bw = new DataOutputStream(socket.getOutputStream());
}
catch(IOException e){
System.err.println(e.toString());
System.exit(1);
}
}
//run()方法
public void run(){
try{
bw.writeInt(clientID);
}
catch(IOException e){
System.err.println(e.toString());
System.exit(1);
}
//循环读一用户的信息,并把它发送给其他用户
while(true){
try{
//读对应的用户发送过来的信息
String message = br.readUTF();
//发送给其他用户
for(int i=0;i<clientNum;i++){
communicationThread[i].bw.writeUTF("客户" + clientID + ":" + message);
}
if(message != null && message.equals("bye"))
break;
}
catch(IOException e){
System.err.println(e.toString());
System.exit(1);
}
}
try{
bw.close();
br.close();
socket.close();
}
catch(EOFException e){
System.err.println(e.toString());
}
catch(IOException e){
System.err.println(e.toString());
}
}
}


public static void main(String args[]){
new Server();
}
}

以下是客户端的代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;


public class Client extends JFrame implements Runnable{
private int clientID;
private String clientWord;
private JPanel topPanel;
private JLabel nameLabel;
private JTextField wordField;
private JButton submit;
private JTextArea displayField;
private Socket socket;
private DataInputStream br;
private DataOutputStream bw;
//构造面板
public Client(){
Container container = getContentPane();
container.setLayout(new BorderLayout(5,5));
topPanel = new JPanel(new FlowLayout());
nameLabel = new JLabel("");
wordField = new JTextField(20);
submit = new JButton("发送");
submit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
try{
String sentence = wordField.getText();
bw.writeUTF(sentence);
}
catch(IOException e){
System.err.println(e.toString());
}
}
});
topPanel.add(nameLabel);
topPanel.add(wordField);
topPanel.add(submit);
displayField = new JTextArea();
container.add(topPanel,BorderLayout.NORTH);
container.add(displayField,BorderLayout.CENTER);
setSize(400,500);
setResizable(false);
setVisible(true);
}
//主方法
public static void main(String args[]){
Client clientWindow = new Client();
clientWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
clientWindow.nor();
}
//创建线程和socket连接
public void nor(){
Thread commThread = new Thread(this);
commThread.start();
try{
socket = new Socket("127.0.0.1",10000);
br = new DataInputStream(socket.getInputStream());
bw = new DataOutputStream(socket.getOutputStream());
}
catch(IOException e){
System.err.println(e.toString());
}
}
//run方法
public void run(){
try{
//设置Label的文本
clientID = br.readInt();
SwingUtilities.invokeLater(new Runnable(){
public void run(){
nameLabel.setText("客户" + clientID);
}
});
//循环读服务端发来的信息
while(true){
clientWord = br.readUTF();
displayMessage(clientWord);
}
}
catch(EOFException e){
System.err.println(e.toString());
}
catch(IOException e){
System.err.println(e.toString());
}
}
//把信息显示出来
private void displayMessage(final String message){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
displayField.append(message + "\n");
displayField.setCaretPosition(displayField.getText().length());
}
});
}
}

请高手帮帮忙,我的目的是创建一个多用户在线聊天的程序,可以启动多个客户端,客户端的信息都发给服务端,再让服务端发给所有的用户,但是奇怪的是,我先启动服务端的程序(服务端程序启动没问题),再启动客户端的程序,有时可以正常启动,有时却会抛出异常,异常如下所示

关于java多用户在线聊天程序的问题。。

13 个解决方案

#1


异常的内容是:
Exception in thread "Thread-3" java.lang.NullPointerException
        at Client.run(Client.java.67)
        at java.lang.Thread.run(Unknown Source)

#2


哦不是,是第71行,也就是clientID = br.readInt();这一行

#3


Client.java.67抛空指针了啊,检查

#4


你clientID = br.readInt();这里的br是null,

#5


你客户端的程序,核心部分是:

    public void nor(){
        Thread commThread = new Thread(this);
        commThread.start(); // 启动线程
        try{
            socket = new Socket("127.0.0.1",10000);
            br = new DataInputStream(socket.getInputStream()); // 然后才初始化br
            bw = new DataOutputStream(socket.getOutputStream());
        }
        catch(IOException e){
            System.err.println(e.toString());
        }
    }
    public void run(){
        try{
            //设置Label的文本
            clientID = br.readInt(); // 碰运气语句


如果子线程(run()函数)执行的比你主线程快,你这句话必然空指针。

偷懒的改法,可以在run()函数最前面,加上 Thread.sleep(100); 先睡100毫秒,相当于等主线程。

#6


该回复于2012-04-09 09:46:25被版主删除

#7


不可否认你代码排版的很清晰。。。
我觉得首要任务是去连服务器,而不是先打开线程开始监听输入输出流。

    public void nor(){
        
        try{
            socket = new Socket("127.0.0.1",10000);
            br = new DataInputStream(socket.getInputStream());
            bw = new DataOutputStream(socket.getOutputStream());
            Thread commThread = new Thread(this);
            commThread.start();
        }
        catch(IOException e){
            System.err.println(e.toString());
        }
    }


#8


引用 7 楼  的回复:
不可否认你代码排版的很清晰。。。
我觉得首要任务是去连服务器,而不是先打开线程开始监听输入输出流。
Java code

    public void nor(){
        
        try{
            socket = new Socket("127.0.0.1",10000);
            br = new DataInputStream(s……

受教了!

#9


该回复于2012-04-08 14:23:30被版主删除

#10


引用 5 楼  的回复:
你客户端的程序,核心部分是:

Java code
    public void nor(){
        Thread commThread = new Thread(this);
        commThread.start(); // 启动线程
        try{
            socket = new Socket("127.0.0.1",10000);
……

这位大虾今天已经是第二次回答我的帖子了,谢谢啊~那么请让我再请教一个问题。。在我服务端代码那边,我循环给每个客户端发送信息,可是,不是要关闭输出流才能把信息发送出去的吗?在那个总为true的while里面,只要信息不是“bye”,都不会跳出while循环,也就是不会执行bw.close();,可是现在客户端又能正确接收到服务端的信息,这又是怎么回事?

#11


引用 4 楼  的回复:
你clientID = br.readInt();这里的br是null,

确实如此!

#12


不一定是close才会发送信息,而是close时一定会发送信息;两句话不能等同对待。

但从性能出发,一般是缓冲区满才会进行真实发送。

所以从稳定的角度来说,可以写bw.flush();

#13


引用 12 楼  的回复:
不一定是close才会发送信息,而是close时一定会发送信息;两句话不能等同对待。

但从性能出发,一般是缓冲区满才会进行真实发送。

所以从稳定的角度来说,可以写bw.flush();

多谢你们的回答!!!

#1


异常的内容是:
Exception in thread "Thread-3" java.lang.NullPointerException
        at Client.run(Client.java.67)
        at java.lang.Thread.run(Unknown Source)

#2


哦不是,是第71行,也就是clientID = br.readInt();这一行

#3


Client.java.67抛空指针了啊,检查

#4


你clientID = br.readInt();这里的br是null,

#5


你客户端的程序,核心部分是:

    public void nor(){
        Thread commThread = new Thread(this);
        commThread.start(); // 启动线程
        try{
            socket = new Socket("127.0.0.1",10000);
            br = new DataInputStream(socket.getInputStream()); // 然后才初始化br
            bw = new DataOutputStream(socket.getOutputStream());
        }
        catch(IOException e){
            System.err.println(e.toString());
        }
    }
    public void run(){
        try{
            //设置Label的文本
            clientID = br.readInt(); // 碰运气语句


如果子线程(run()函数)执行的比你主线程快,你这句话必然空指针。

偷懒的改法,可以在run()函数最前面,加上 Thread.sleep(100); 先睡100毫秒,相当于等主线程。

#6


该回复于2012-04-09 09:46:25被版主删除

#7


不可否认你代码排版的很清晰。。。
我觉得首要任务是去连服务器,而不是先打开线程开始监听输入输出流。

    public void nor(){
        
        try{
            socket = new Socket("127.0.0.1",10000);
            br = new DataInputStream(socket.getInputStream());
            bw = new DataOutputStream(socket.getOutputStream());
            Thread commThread = new Thread(this);
            commThread.start();
        }
        catch(IOException e){
            System.err.println(e.toString());
        }
    }


#8


引用 7 楼  的回复:
不可否认你代码排版的很清晰。。。
我觉得首要任务是去连服务器,而不是先打开线程开始监听输入输出流。
Java code

    public void nor(){
        
        try{
            socket = new Socket("127.0.0.1",10000);
            br = new DataInputStream(s……

受教了!

#9


该回复于2012-04-08 14:23:30被版主删除

#10


引用 5 楼  的回复:
你客户端的程序,核心部分是:

Java code
    public void nor(){
        Thread commThread = new Thread(this);
        commThread.start(); // 启动线程
        try{
            socket = new Socket("127.0.0.1",10000);
……

这位大虾今天已经是第二次回答我的帖子了,谢谢啊~那么请让我再请教一个问题。。在我服务端代码那边,我循环给每个客户端发送信息,可是,不是要关闭输出流才能把信息发送出去的吗?在那个总为true的while里面,只要信息不是“bye”,都不会跳出while循环,也就是不会执行bw.close();,可是现在客户端又能正确接收到服务端的信息,这又是怎么回事?

#11


引用 4 楼  的回复:
你clientID = br.readInt();这里的br是null,

确实如此!

#12


不一定是close才会发送信息,而是close时一定会发送信息;两句话不能等同对待。

但从性能出发,一般是缓冲区满才会进行真实发送。

所以从稳定的角度来说,可以写bw.flush();

#13


引用 12 楼  的回复:
不一定是close才会发送信息,而是close时一定会发送信息;两句话不能等同对待。

但从性能出发,一般是缓冲区满才会进行真实发送。

所以从稳定的角度来说,可以写bw.flush();

多谢你们的回答!!!