java实现简易聊天窗口先运行服务器还是客户端_一个简易聊天功能的服务器端和客户端源码...
學(xué)習(xí)完J2SE可以寫一個簡易的聊天軟件來讓剛學(xué)的知識融會貫通,代碼注釋的很詳細(xì)哦!
開發(fā)版本歷程:
V0.1:客戶端實現(xiàn)一個界面
V0.2:客戶端界面有輸入框和顯示框的界面
V0.3:客戶端關(guān)閉按鈕可以關(guān)閉窗口
V0.4:客戶端按回車后輸入框的文字顯示在顯示框
V0.5:服務(wù)端能夠起一個服務(wù)監(jiān)聽某端口
V0.6:客戶端能夠連接到服務(wù)器端
V0.7:客戶端發(fā)一條消息,服務(wù)端能夠接收到
V0.8:服務(wù)器端能到接收多條來自客戶端的消息,改善V0.7的只能接受一條消息
V0.9:客戶端關(guān)閉后,服務(wù)器端采取相應(yīng)的措施,是服務(wù)器端不報錯
V1.0:服務(wù)器端可以連接多個客戶端,并且可以接收到來自每個客戶端發(fā)送的消息
V1.1:服務(wù)器端把接收到每個客戶端的消息發(fā)送出去
V1.2:每個客戶端都能接收來自服務(wù)器的數(shù)據(jù),并顯示在顯示框
V1.3:檢查一些異常并修復(fù)(下面的代碼就是這個版本)
注:代碼還有很多改進(jìn)的地方,這只是一個簡易的版本
聊天服務(wù)器端代碼:
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer {
boolean started = false;
ServerSocket ss = null;
List clients = new ArrayList();
public static void main(String[] args){
new ChatServer().start(); //不能直接這樣調(diào)用start()
}
public void start(){
try {
ss = new ServerSocket(8888); //在端口8888建立監(jiān)聽
started = true; //建立監(jiān)聽成功令此變量為真
}catch (SocketException e){
System.out.println("端口使用中。。。");
System.out.println("請關(guān)掉相關(guān)程序!");
System.exit(0);
}catch (IOException e) {
e.printStackTrace();
}
try{
while(started){
Socket s = ss.accept(); //***重要***若此處報錯,嘗試用360進(jìn)行LSP修復(fù)
Client c = new Client(s); //每接受一個客戶端就會new一個線程
System.out.println("a client connected");
new Thread(c).start(); //啟動線程,start()方法只是啟動線程,而線程中的run()方法這是實現(xiàn)此線程功能的代碼
clients.add(c);
}
}catch (IOException e) {
e.printStackTrace();
}finally{
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//定義一個線程內(nèi)部類
class Client implements Runnable{
private Socket s;
private DataInputStream dis = null;
private DataOutputStream dos = null;
private boolean bConnected = false;
public Client(Socket s){
this.s=s;
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
bConnected = true; // 有一個客戶端連上后另此變量為真
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String str){
try {
dos.writeUTF(str);
} catch (IOException e) {
clients.remove(this);//防止有一個客戶端退出了,其他客戶端還在發(fā)消息,此時List里面還有這個退出的客戶端,服務(wù)器就會報錯
System.out.println("對方退出了,已經(jīng)從List里面去除了!");
}
}
public void run() {
try {
while (bConnected) {
String str = dis.readUTF(); //readUTF()是一個阻塞式的,main方法執(zhí)行到此處就一直一行一行的讀,程序停在此處
System.out.println(str);
for(int i = 0; i < clients.size(); i++){
Client c = clients.get(i);
c.send(str);
}
}
}catch(EOFException e){
System.out.println("Client closed!");
}catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(dis != null) dis.close();
if(dos != null) dos.close();
if(s != null) s.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
聊天客戶端代碼:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
//客戶端ChatClient
public class ChatClient extends Frame{
//響應(yīng)他的事件,需要去訪問他的內(nèi)容,所以定義為成員變量
TextField tfTxt = new TextField();
TextArea taContent = new TextArea();
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
private boolean bConnected = false;
Thread tRecv = new Thread(new RecvThread());
public static void main(String[] args) {
new ChatClient().launchFrame();
}
//運行客戶端窗口的方法
public void launchFrame(){
this.setLocation(400,300);
setSize(300,300);
add(tfTxt,BorderLayout.SOUTH); //BorderLayout為Frame默認(rèn)布局管理器。調(diào)用其他應(yīng)調(diào)用setLayout(某個布局管理器對象)
add(taContent,BorderLayout.NORTH);
pack(); //如果沒有pack();則兩個控件中有空的部分
//使用匿名類添加窗口的事件監(jiān)聽器,注意WindowAdapter()的使用,windowClosing將要關(guān)閉窗口
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
disconnect();
System.exit(0);
}
});
//把監(jiān)聽器添加在文本框上,此時回車直接返回對象的信息,不需要添加Enter的KeyListener
tfTxt.addActionListener(new TFListener());
setVisible(true);
connect();
tRecv.start();
}
public void connect(){
try {
s = new Socket("127.0.0.1",8888);
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
System.out.println("connected!");
bConnected = true;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
dos.close();
dis.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private class TFListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String str = tfTxt.getText().trim(); //String里面的方法trim()去掉兩邊的空格
tfTxt.setText(""); //設(shè)置一個空字符串,讓文本框里面的內(nèi)容為空
try {
dos.writeUTF(str);
dos.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
private class RecvThread implements Runnable {
@Override
public void run() {
try {
while (bConnected) {
String str = dis.readUTF();
taContent.setText(taContent.getText() + str + '\n');
}
} catch(SocketException e){
System.out.println("退出了,bye!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
總結(jié)
以上是生活随笔為你收集整理的java实现简易聊天窗口先运行服务器还是客户端_一个简易聊天功能的服务器端和客户端源码...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10玩游戏掉帧严重怎么处理(cf卡
- 下一篇: 礼仪存单和定期存单的区别