1. 程式人生 > >Java中的Socket.、執行緒和HaspMap的使用

Java中的Socket.、執行緒和HaspMap的使用

Java中的Socket.、執行緒和HaspMap的使用

程式的功能:實現多人聊天

關鍵技術點說明:伺服器將每個客戶端的執行緒儲存在hashmap中,這樣就能實現資料正確轉發到哪個視窗。客戶端這邊將連線伺服器的執行緒也儲存起來,同時還要儲存執行緒對應的聊天介面,這樣通過讀取連線伺服器的執行緒就能正確收到訊息,通過執行緒對應的介面就能將訊息正確的顯示。通過這個例項熟悉一下面向物件程式設計。

程式關鍵程式碼實現:

服務端:

1.伺服器建立ServerSocket 

public class MyQqServer {

public MyQqServer()

{

try {

ServerSocket ss=new ServerSocket(3456);

while(true)

{

Socket s=ss.accept();

ObjectInputStream ois=new ObjectInputStream(s.getInputStream());

User u=(User)ois.readObject();

Message m=new Message();

ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());

if(u.getPasswd().equals("12"))

{

m.setMessType("1");

oos.writeObject(m);

SerConClientThread scct=new SerConClientThread(s);

ManageClientThread.addClientThread(u.getUserid(), scct);

scct.start();

scct.notifyother(u.getUserid());

}else 

{

m.setMessType("2");

oos.writeObject(m);

s.close();

}

  }

} catch (Exception e) {

// TODO: handle exception

}finally{

}

}

2.將客戶端的執行緒放進

HashMap

public class ManageClientThread {

public static HashMap<String, SerConClientThread> hm=new HashMap<String,SerConClientThread>();

public static void addClientThread(String uid,SerConClientThread ct)

{

hm.put(uid, ct);

}

public static SerConClientThread getClientThread(String uid)

{

return (SerConClientThread)hm.get(uid);

}

public static String getAllOnLineUserid()

{

Iterator<String> it=hm.keySet().iterator();

String res="";//問題所在 “ ” 這個是錯的

while(it.hasNext())

{

res+=it.next().toString()+" ";

}

return res;

}

}

3.當有一個客戶端連線進來的時候就建立一個執行緒

public class SerConClientThread extends Thread{

Socket s;

public SerConClientThread(Socket s){

//把伺服器和該客戶端的連線賦給s

this.s=s;

}

//讓該執行緒去通知其他使用者

public void notifyother(String iam)

{

HashMap<String, SerConClientThread> hm=ManageClientThread.hm;

Iterator<String> it=hm.keySet().iterator();

while(it.hasNext())

{

Message m=new Message();

m.setCon(iam);

m.setMessType(MessageType.message_ret_onLineFriend);

String onLineUserId=it.next().toString();

try {

ObjectOutputStream oos=new ObjectOutputStream(ManageClientThread.getClientThread(onLineUserId).s.getOutputStream());

m.setGetter(onLineUserId);

oos.writeObject(m);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

public void run(){

while(true){

try {

ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

Message m = (Message) ois.readObject();

if(m.getMessType().equals(MessageType.message_comm_mes))

{

//取得接收人的執行緒  實現轉發    ( SerConClientThread是連線的執行緒 在MyQqServer時候被建立)

SerConClientThread sc=ManageClientThread.getClientThread(m.getGetter());

ObjectOutputStream oos=new ObjectOutputStream(sc.s.getOutputStream());

oos.writeObject(m);

}else if(m.getMessType().equals(MessageType.message_get_onLineFriend))

{

//把在伺服器的好友返回給該客戶端

String res=ManageClientThread.getAllOnLineUserid();

Message m1=new Message();

m1.setMessType(MessageType.message_ret_onLineFriend);

m1.setCon(res);

m1.setGetter(m.getSender());//服務端發給客服端,客戶端是getter, sengder是客戶端發的

ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());

oos.writeObject(m1);

}

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}

}

}

}

客戶端:

1客戶端與伺服器的執行緒放在HashMap,保持聊天介面中是將執行緒對應的介面放進HashMap

public class ManageClientConServerThread {

private static HashMap<String, ClientConServerThread> hm=new HashMap<String,ClientConServerThread>();

//把建立好的ClientConServerThread放入到hm

public static void addClientConServerThread(String qqId,ClientConServerThread ccst)

{

hm.put(qqId, ccst);

}

//可以通過qqId取得該執行緒 

public static ClientConServerThread getClientConServerThread(String qqId)

{

return (ClientConServerThread)hm.get(qqId);

}

}

2.這是客戶端接收伺服器訊息線上程中的實現程式碼

public class ClientConServerThread extends Thread{

private Socket s;

public Socket getS() {

return s; 

}

public void setS(Socket s) {

this.s = s;

}

public ClientConServerThread(Socket s){

this.s=s;

}

public void run(){

while(true)

{

try {

//不停的讀取從伺服器端發來的訊息

ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

Message m = (Message) ois.readObject();

// System.out.println("讀取到從服務發來的訊息"+ m.getSender() +" 給 "+m.getGetter()+" 內容"+m.getCon());

//把從伺服器獲得的訊息,顯示到該顯示的聊天介面

if(m.getMessType().equals(MessageType.message_comm_mes))

{

QqChat qqChat=ManageQqChat.getQqChat(m.getGetter()+" "+m.getSender());//這邊是接收 ,所以getGetterlogin自己

qqChat.showMessage(m);

}else if(m.getMessType().equals(MessageType.message_ret_onLineFriend)){

System.out.println("客戶端接收到的資訊"+m.getCon());

String con=m.getCon();

String friends[]=con.split(" ");

String getter=m.getGetter();//返回給傳送者, 就是要得到好友列表的send

//修改相應的好友列表

QqFriendList qqFriendList=ManageQqFriendList.getQqFriendList(getter);

//更新好友類表

if(qqFriendList!=null){

qqFriendList.updataFriend(m);

}

}

} catch (Exception e) {

e.printStackTrace();

// TODO: handle exception

}

}

}

}

3.客戶端連線伺服器的實現

public class QqClientConServer {

public Socket s;

public boolean  sendLoginInfoToServer(Object o)

{

boolean b=false;

try{

s = new Socket("211.80.180.73", 3456);

ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());

oos.writeObject(o);

System.out.print(o);

System.out.println("客服端傳送成功");

ObjectInputStream ois=new ObjectInputStream(s.getInputStream());

Message ms=(Message)ois.readObject();

System.out.println("收到的資訊型別"+ms.getMessType());

if(ms.getMessType().equals("1"))

{

//就建立一個該qq號和伺服器保持通訊的連線執行緒

ClientConServerThread ccst=new ClientConServerThread(s);

// ManageClientConServerThread d=new ManageClientConServerThread();

// d.addClientConServerThread(((User)o).getUserid(), ccst);//證明了是STATIC 可以直接用  在編譯時已經例項化

ManageClientConServerThread.addClientConServerThread(((User)o).getUserid(), ccst);

ccst.start();

b=true;

}else{

// s.close();

}

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}finally{

}

return b;

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

未完成:好多

計劃:計算器