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.將客戶端的執行緒放進
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());//這邊是接收 ,所以getGetter是login自己
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;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
未完成:好多
計劃:計算器