这是本人近期学期的一个总结,有什么讲的不妥之处请各位指出,感谢。
关于聊天室的代码网上也是一抓一大把,但是真正的能讲清楚初学者的想掌握的要点的文章还是有点少,在做之前也查了很多资料。首先,要做这个聊天室,你需要掌握的知识点有集合,泛型,服务器套接字,io,线程,swing以及异常捕获。聊天室的构成一般会有三部分组成,一般就是界面(Frame),聊天服务器(ChatServer)和聊天客户端(ChatClient)组成。在等会的代码中,我分为服务器和客户端两个方面,如果想做的好点就做三个class文件。服务器方面,我先用了用了一个Arraylist来存储客户端这个对象,
这边有个知识点就是为什么集合要用LIst呢,首先list主要的功能是用于储存,但Map主要用于建立对象的关联,Set的每种对象类型只能持有一个,So。然后就是用到了父类声明创建子类对象。接下来就是给给服务器指定本地端口,一共有65536个。然后让服务器死循环,用于不停的监听外面的客户端接入请求。每当接受客户端请求后就把它加入到当前的集合中,其实集合也就是个容器。接下来有客户端连入后,我们势必要做一个线程让服务器能够接受客户端发出的消息,然后把接收的消息发给其他的客户端中。其中这边的知识点就是当有多个客户端连入时,但谁在发出消息的那个时候线程应处于阻塞状态,防止两个客户端的消息被一起接收,然后出现异常,就像两个电脑要打印文件,不可能在一个打印机上同时打印。对于输入流输出流,就是服务器要不停的准备接受消息,如果没有死循环,消息就是每个客户端发一次就不能发了。然后输出流方面就是不要忘记刷新,不然消息也是会发不出的,对于这个我当时烦了一天,因为知识点没掌握,发现其他的io可以,就是bufferreader和printwriter不可以,就是没刷新,导致数据写入了缓冲区中,却没刷新发出去。至于客户端方面,基本没什么大的问题了,连入本地服务器端口,然后输出流放在发送的按钮中。记得流要关闭,先开后关。至于swing方面,我了解的不多,但是好像现在不怎么用了,所以没什么要讲的啦。上代码
public class ChatServer {
List<ClientThread> clients = new ArrayList<ClientThread>();
public static void main(String[] args) {
new ChatServer().go();
}
public void go(){
try {
ServerSocket serversocket = new ServerSocket(12345);
while(true){
System.out.println("端口绑定");
Socket socket = serversocket.accept();
System.out.println("有外部客户端接入");
ClientThread currentClient = new ClientThread(socket);
clients.add(currentClient);
currentClient.start();
System.out.println("客户端线程开始");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class ClientThread extends Thread{
private Socket socket;
private BufferedReader bis;
private PrintWriter bos;
private String line;
public ClientThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
System.out.println("run方法启动了!");
try {
while(true){
bis = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
line = bis.readLine();
System.out.println("接收到消息");
for(int i=0; i<clients.size(); i++){
ClientThread c = clients.get(i);
c.send(line);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void send(String line){
try {
bos = new PrintWriter(
new OutputStreamWriter(
socket.getOutputStream()));
bos.println(line);
bos.flush();
System.out.println("正在向客户端写消息成功!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ChatClient {
private JTextArea ta;
private JTextField tf;
private JButton b;
private BufferedReader bis;
private PrintWriter bos;
private Socket socket;
public static void main(String[] args) {
new ChatClient().frame();
}
public void frame(){
JFrame f = new JFrame("BB");
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
ta = new JTextArea(12, 30); // 文本域,第一个参数为行数,第二个参数为列数
ta.setEditable(false); // 文本域只读
JScrollPane sp = new JScrollPane(ta); // 滚动窗格
tf = new JTextField(20);
b = new JButton("发送");
p1.add(sp);
p2.add(tf);
p2.add(b);
f.add(p1, "Center");
f.add(p2, "South");
f.setBounds(300, 300, 360, 300);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.b.addActionListener(new TFListener());
this.connect();
}
public void connect(){
try {
socket = new Socket("127.0.0.1", 12345);
bos = new PrintWriter(
(socket.getOutputStream()));
bis = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
new sendThread().start();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class TFListener implements ActionListener{
private String str;
@Override
public void actionPerformed(ActionEvent e) {
str = tf.getText()+"\n";
tf.setText("");
// ta.append(str);
bos.println(str);
bos.flush();
}
}
class sendThread extends Thread{
private String str;
@Override
public void run() {
recMsg();
}
public void recMsg(){
try {
while(true){
str = bis.readLine()+"\n";
ta.append(str);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}