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());
}
});
}
}
请高手帮帮忙,我的目的是创建一个多用户在线聊天的程序,可以启动多个客户端,客户端的信息都发给服务端,再让服务端发给所有的用户,但是奇怪的是,我先启动服务端的程序(服务端程序启动没问题),再启动客户端的程序,有时可以正常启动,有时却会抛出异常,异常如下所示
13 个解决方案
#1
异常的内容是:
Exception in thread "Thread-3" java.lang.NullPointerException
at Client.run(Client.java.67)
at java.lang.Thread.run(Unknown Source)
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
你客户端的程序,核心部分是:
如果子线程(run()函数)执行的比你主线程快,你这句话必然空指针。
偷懒的改法,可以在run()函数最前面,加上 Thread.sleep(100); 先睡100毫秒,相当于等主线程。
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
#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
受教了!
#9
#10
这位大虾今天已经是第二次回答我的帖子了,谢谢啊~那么请让我再请教一个问题。。在我服务端代码那边,我循环给每个客户端发送信息,可是,不是要关闭输出流才能把信息发送出去的吗?在那个总为true的while里面,只要信息不是“bye”,都不会跳出while循环,也就是不会执行bw.close();,可是现在客户端又能正确接收到服务端的信息,这又是怎么回事?
#11
确实如此!
#12
不一定是close才会发送信息,而是close时一定会发送信息;两句话不能等同对待。
但从性能出发,一般是缓冲区满才会进行真实发送。
所以从稳定的角度来说,可以写bw.flush();
但从性能出发,一般是缓冲区满才会进行真实发送。
所以从稳定的角度来说,可以写bw.flush();
#13
多谢你们的回答!!!
#1
异常的内容是:
Exception in thread "Thread-3" java.lang.NullPointerException
at Client.run(Client.java.67)
at java.lang.Thread.run(Unknown Source)
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
你客户端的程序,核心部分是:
如果子线程(run()函数)执行的比你主线程快,你这句话必然空指针。
偷懒的改法,可以在run()函数最前面,加上 Thread.sleep(100); 先睡100毫秒,相当于等主线程。
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
#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
受教了!
#9
#10
这位大虾今天已经是第二次回答我的帖子了,谢谢啊~那么请让我再请教一个问题。。在我服务端代码那边,我循环给每个客户端发送信息,可是,不是要关闭输出流才能把信息发送出去的吗?在那个总为true的while里面,只要信息不是“bye”,都不会跳出while循环,也就是不会执行bw.close();,可是现在客户端又能正确接收到服务端的信息,这又是怎么回事?
#11
确实如此!
#12
不一定是close才会发送信息,而是close时一定会发送信息;两句话不能等同对待。
但从性能出发,一般是缓冲区满才会进行真实发送。
所以从稳定的角度来说,可以写bw.flush();
但从性能出发,一般是缓冲区满才会进行真实发送。
所以从稳定的角度来说,可以写bw.flush();
#13
多谢你们的回答!!!