一個完整的項目包括服務器和客服端java
服務器端初步編寫:安全
(1)服務器
服務器端應用窗口的編寫 (服務器類Server):this
包括窗口和組件的一些設置, 添加一些客服端的元素,如客服端在線用戶表(Vector), 服務端接口ServerSocket, 服務端線程ServerThread spa
其次就是組件的事件監聽以及相應的事件方法 線程
(2)代理
服務器線程的編寫 (服務器線程類 ServerThread): code
服務器線程起分配服務器代理線程做用,接受客服端的鏈接同時爲其分配一個專用的服務器代理線程.blog
編寫相對簡單,給出服務器(Server) 經過其服務端接口(ServerSocket)監聽客服端的鏈接(Socket),同時爲其分配代理線程(ServerAgentThread)接口
public class ServerThread extends Thread { Server father; //聲明Server的引用 ServerSocket ss;//聲明ServerSocket的引用 boolean flag=true; public ServerThread(Server father) {//構造器 this.father=father; ss=father.ss; } public void run() { while(flag) { try { Socket sc=ss.accept();//等待客戶端鏈接 ServerAgentThread sat=new ServerAgentThread(father,sc); sat.start();//建立並啓動服務器代理線程 } catch(Exception e) { e.printStackTrace(); } } } }
(3)
服務器代理線程(ServerAgentThread) :代理線程對應相應的客服端 起到接受發送信息做用 一個服務器代理線程與一個客服端惟一對應
服務器代理線程類是服務器主要類,
其中包括一些基本的代理線程內容 如服務器(Server) 客服端鏈接(Socket) 數據輸入輸出(DateInputStream DateOutputStream)
還有與客服端的數據的一些交流方法, 線程run方法起判斷客服端信息做用
public class ServerAgentThread extends Thread { Server father;//聲明Server(服務器Server)的引用 Socket sc;//聲明Socke(客服端接口Socket)t的引用 DataInputStream din;//聲明數據輸入流與輸出流 DataOutputStream dout; boolean flag=true;//控制線程的生命週期 public ServerAgentThread(Server father,Socket sc) { //構造方法通常初始化 服務器 客服端接口 還有應用端接口數據輸入輸出 this.father=father; this.sc=sc; try { din=new DataInputStream(sc.getInputStream());//建立數據輸入流 dout=new DataOutputStream(sc.getOutputStream());//建立數據輸出流 } catch(Exception e) { e.printStackTrace(); } } public void run() { while(flag) { try { String msg=din.readUTF().trim(); //接收客戶端傳來的信息判斷並做出相應的迴應 //其中單個迴應通常包含對服務器端的操做數據迴應 以及對客服端的操做數據迴應 if(msg.startsWith("c"))//收到新用戶的信息 { this.nick_name(msg); } else if(msg.startsWith("<#CLIENT_LEAVE#>")){ this.client_leave(msg); } else if(msg.startsWith("<#TIAO_ZHAN#>")){ this.tiao_zhan(msg); } else if(msg.startsWith("<#TONG_YI#>")){ this.tong_yi(msg); } else if(msg.startsWith("<#BUTONG_YI#>")){ this.butong_yi(msg); } else if(msg.startsWith("<#BUSY#>")){ this.busy(msg); } else if(msg.startsWith("<#MOVE#>")){ this.move(msg); } else if(msg.startsWith("<#RENSHU#>")){ this.renshu(msg); } } catch(Exception e) { e.printStackTrace(); } } } //單個操做方法的書寫 //此處省略幾個 //新用戶 public void nick_name(String msg) { try { String name=msg.substring(13);//得到用戶的暱稱 this.setName(name);//用該暱稱給該線程取名 Vector v=father.onlineList;//得到在線用戶列表 boolean isChongMing=false;//重名flag int size=v.size();//得到用戶列表的大小 for(int i=0;i<size;i++) { //遍歷列表,查看是否已經有該用戶名 ServerAgentThread tempSat=(ServerAgentThread)v.get(i); if(tempSat.getName().equals(name)) { isChongMing=true;//有重名,將標誌位設爲true break; } } if(isChongMing==true)//若是重名 { dout.writeUTF("<#NAME_CHONGMING#>");//將重名信息發送給客戶端 din.close();//關閉數據輸入流 dout.close();//關閉數據輸出流 //重點部分 重名須要終止分配的該服務器代理線程以避免產生安全問題 sc.close();//關閉Socket flag=false;//終止該服務器代理線程 } else//若是不重名 { v.add(this);//將該線程添加到在線列表 father.refreshList();//刷新服務器在線信息列表 String nickListMsg=""; size=v.size();//得到在線列表大小 //(實時更新) for(int i=0;i<size;i++) { ServerAgentThread tempSat=(ServerAgentThread)v.get(i); nickListMsg=nickListMsg+"|"+tempSat.getName(); } nickListMsg="<#NICK_LIST#>"+nickListMsg; //將在線用戶組成字符串 <#NICK_LIST#>|1|2|3|4|5|6|7 Vector tempv=father.onlineList; size=tempv.size(); for(int i=0;i<size;i++) {//遍歷在線列表 ServerAgentThread satTemp=(ServerAgentThread)tempv.get(i); satTemp.dout.writeUTF(nickListMsg);//將最新的列表信息發送到各個客戶端 if(satTemp!=this) {//給其餘客戶端發送新用戶上線的信息 satTemp.dout.writeUTF("<#MSG#>"+this.getName()+"上線了..."); } } } } catch(IOException e) { e.printStackTrace(); } } } //用戶下線 public void client_leave(String msg){ try{ Vector tempv=father.onlineList;//得到在線列表 tempv.remove(this);//移除該用戶代理線程 int size=tempv.size(); String nl="<#NICK_LIST#>"; for(int i=0;i<size;i++){//遍歷在線列表 ServerAgentThread satTemp=(ServerAgentThread)tempv.get(i); //向各個客戶端發送用戶離線信息 satTemp.dout.writeUTF("<#MSG#>"+this.getName()+"離線了..."); //組織信息的在線用戶列表 nl=nl+"|"+satTemp.getName(); } for(int i=0;i<size;i++){//將最新的列表信息發送到各個客戶端 ServerAgentThread satTemp=(ServerAgentThread)tempv.get(i); satTemp.dout.writeUTF(nl); } (重點部分 線程下線須要關閉其相關代理) this.flag=false;//終止該服務器代理線程 father.refreshList();//更新服務器在線用戶列表 } catch(IOException e){e.printStackTrace();} }