准備工作:
1.在服務端和客戶端項目中都建立中間傳遞對象,implements序列化
1 public class ContextDemo implements Serializable { 2 3 // 0:上線 1:發送信息 2:下線 3:抖窗 4:發送文件 4 private int type; 5 private HashSet<String> clients; 6 private String info; 7 private String name; 8 private String time; 9 private String last; 10 private ArrayList<Byte> list2; 11 12 public String getLast() { 13 return last; 14 } 15 16 public void setLast(String last) { 17 this.last = last; 18 } 19 public ArrayList<Byte> getList2() { 20 return list2; 21 } 22 23 public void setList2(ArrayList<Byte> list2) { 24 this.list2 = list2; 25 } 26 27 public String getName() { 28 return name; 29 } 30 31 public void setName(String name) { 32 this.name = name; 33 } 34 35 public int getType() { 36 return type; 37 } 38 39 public void setType(int type) { 40 this.type = type; 41 } 42 43 public HashSet<String> getClients() { 44 return clients; 45 } 46 47 public void setClients(HashSet<String> clients) { 48 this.clients = clients; 49 } 50 51 public String getInfo() { 52 return info; 53 } 54 55 public void setInfo(String info) { 56 this.info = info; 57 } 58 59 public String getTime() { 60 return time; 61 } 62 63 public void setTime(String time) { 64 this.time = time; 65 } 66 67 }
2.服務端實現監聽
服務端靜態創建一個可以監聽客戶端連接的serversocket和可以存儲在線用戶名與socket的Hashmap,服務端開啟監聽,並在監聽到任意客戶端的連接時開啟一個新的服務端監聽線程(將該用戶的socket通過構造函數傳遞給這個線程)
1 public static ServerSocket ss; 2 public static HashMap<String, Socket> online; 3 public static Socket socket; 4 5 static { 6 try { 7 ss = new ServerSocket(8080); 8 System.out.println("服務器已開啟"); 9 online = new HashMap<String, Socket>(); 10 } catch (IOException e) { 11 e.printStackTrace(); 12 } 13 } 14 15 public void action() { 16 try { 17 while (true) { 18 Socket s = ss.accept(); 19 System.out.println("服務器正在監聽"); 20 new Server_Thread(s).start(); 21 } 22 } catch (IOException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } 26 } 27 28 public static void main(String[] args) { 29 30 new Chat_Server().action(); 31 32 }
線程中定義
(1)發送給全部在線用戶的方法,主要是通過創建Hashmap的iterator來實現遍歷,獲取到每一個在線用戶的socket,並用這個用戶的socket來建立outputstream進行消息的傳遞
1 // 定義發送給全部用戶的方法 2 public void sendtoall(ContextDemo servercontext) { 3 Collection<Socket> clients = online.values(); 4 Iterator<Socket> iterator = clients.iterator(); 5 ObjectOutputStream oo; 6 while (iterator.hasNext()) { 7 8 Socket socket = iterator.next(); 9 try { 10 oo = new ObjectOutputStream(socket.getOutputStream()); 11 oo.writeObject(servercontext); 12 oo.flush(); 13 } catch (IOException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } 17 } 18 }
(2)發送給指定用戶的方法,方法實現與發送給全部用戶的方法基本一致,只是需要進行判斷,如果選中的用戶中包含遍歷出來的在線用戶,再取socket進行發送
1 // 定義發送給指定用戶的方法 2 public void sendtothis(ContextDemo servercontext) { 3 HashSet<String> clients = clientcontext.getClients(); 4 Set<String> oo = online.keySet(); 5 Iterator<String> it = oo.iterator(); 6 //如果用的同一個輸出流對象,可能會因前一個未寫完而發生錯誤 7 ObjectOutputStream ooo; 8 while (it.hasNext()) { 9 String name = it.next(); 10 if (clients.contains(name)) { 11 Socket s = online.get(name); 12 try { 13 ooo = new ObjectOutputStream(s.getOutputStream()); 14 ooo.writeObject(servercontext); 15 ooo.flush(); 16 } catch (IOException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 } 21 } 22 }
注意:此時應該在其中單獨定義一個objectoutputstream,因為寫出的時候有時間差!!!此bug耗費10小時尋找!!!!(關掉一個客戶端後,另外一個報IOexcption)
線程開始不停地監聽從客戶端發過來的信息(中間傳遞對象),並判斷type,通過switch語句執行不同的操作
1 @Override 2 public void run() { 3 try { 4 while (true) { 5 in = new ObjectInputStream(socket.getInputStream()); 6 clientcontext = (ContextDemo) in.readObject(); 7 8 // 分析type的種類,來用以判斷執行哪種操作 9 switch (clientcontext.getType()) {
一、注冊
界面:
獲取到用戶輸入的用戶名密碼,進行一系列的判斷,與配置文件中的數值進行比對,如果無誤則保存當前用戶輸入的用戶名、密碼進配置文件,並成功登陸到聊天室界面(通過構造函數傳遞socket和username),否則則報錯
1 try { 2 Properties userPro = new Properties(); 3 userPro.load(new FileInputStream("Users.properties")); 4 5 String username = usertext.getText(); 6 String passwordFirst = new String(password1.getPassword()); 7 String passwordLast = new String(password2.getPassword()); 8 9 if (username.length() != 0) { 10 11 if (userPro.containsKey(username)) { 12 JOptionPane.showMessageDialog(getContentPane(), "用戶名已經存在!"); 13 } else { 14 15 if(passwordFirst.equals(passwordLast)){ 16 if(passwordFirst.length()!=0){ 17 userPro.setProperty(username, passwordFirst); 18 userPro.store(new FileOutputStream("Users.properties"), "用戶名——密碼"); 19 20 //進入聊天界面 21 Socket socket = new Socket("localhost", 8080); 22 ChatRoom chatRoom = new ChatRoom(username,socket); 23 chatRoom.setVisible(true); 24 setVisible(false); 25 }else { 26 JOptionPane.showMessageDialog(getContentPane(), "密碼不能為空"); 27 } 28 }else { 29 JOptionPane.showMessageDialog(getContentPane(), "兩次輸入密碼不一致"); 30 } 31 } 32 } else { 33 JOptionPane.showMessageDialog(getContentPane(), "用戶名不能為空"); 34 } 35 } 36 catch (FileNotFoundException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } catch (IOException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 }
二、登錄
界面:
用戶輸入用戶名和密碼,此時通過與項目自帶的properties配置文件中的內容進行比對,如果有記錄,則可以進入到聊天室(通過設置了每個testfield和登錄按鈕的keypressed事件,可通過檢測按下回車按鈕進入),若沒有,則要求進入注冊界面。
注意:如可以進入到聊天室界面,需要將此時新建的socket和用戶名通過聊天室界面的構造函數傳給聊天室。
1 try { 2 Properties properties = new Properties(); 3 properties.load(new FileInputStream("Users.properties")); 4 5 String usernameString = textusername.getText(); 6 String pasString = new String(password1.getPassword()); 7 8 if(properties.containsKey(usernameString)){ 9 if(properties.getProperty(usernameString).equals(pasString)){ 10 Socket socket = new Socket("localhost", 8080); 11 ChatRoom chatRoom = new ChatRoom(usernameString,socket); 12 chatRoom.setVisible(true); 13 setVisible(false); 14 }else { 15 JOptionPane.showMessageDialog(getContentPane(), "密碼輸入錯誤"); 16 } 17 }else { 18 JOptionPane.showMessageDialog(getContentPane(), "該用戶名不存在"); 19 }
三、聊天室主界面
界面:
1.本用戶上線報告服務器+服務器將該用戶上線信息發送給全部用戶
(1)客戶端的構造函數中,將本用戶的socket,用戶名,當前系統時間,中間傳遞對象的類型(上線類型為0),封裝進中間傳遞對象並通過socket的outputstream發送給服務端,並開啟客戶端線程進行監控服務端傳過來的信息
1 // 上線則匯報給服務器 2 try { 3 4 out = new ObjectOutputStream(socket.getOutputStream()); 5 // 創建傳輸對象 6 ContextDemo clientcontext = new ContextDemo(); 7 clientcontext.setType(0); 8 clientcontext.setName(username); 9 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 10 clientcontext.setTime(sdf.format(new Date())); 11 // 發送給服務端 12 out.writeObject(clientcontext); 13 out.flush(); 14 // 開啟客戶端線程 15 new Client_Thread().start(); 16 17 } catch (IOException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 }
客戶端線程開始監聽
1 @Override 2 public void run() { 3 4 try { 5 while (true) { 6 System.out.println("客戶端線程啟動"); 7 in = new ObjectInputStream(socket.getInputStream()); 8 final ContextDemo servercontext = (ContextDemo) in.readObject(); 9 switch (servercontext.getType()) {
(2)服務端得到該用戶的中間傳遞對象,判斷出執行上線操作,執行相應的switch語句,將用戶名與socket存入hashmap,並創建當前用戶的上線信息,對象類型type,以及在線用戶名的集合封裝進對象發送給所有的在線用戶
1 // 上線 2 case 0: 3 // 添加在線用戶進online 4 { 5 6 online.put(clientcontext.getName(), socket); 7 8 ContextDemo serverContext = new ContextDemo(); 9 // 將用戶上線信息發送給各客戶端 10 serverContext.setType(0); 11 serverContext.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + " 上線啦!"); 12 // 將在線用戶用戶名全部發給客戶端 13 HashSet<String> set = new HashSet<String>(); 14 set.addAll(online.keySet()); 15 serverContext.setClients(set); 16 sendtoall(serverContext); 17 break; 18 }
(3)客戶端監聽到信息,判斷出為上下線更新操作,先清空在線列表集合,在將所要取得的各種信息從對象中取得,並獲取到在線人數集合中數目以實現在線人數顯示,並將上線消息顯示在testArea中
1 case 0: 2 // 重新裝填容器 3 { 4 // 清空容器 5 online.clear(); 6 HashSet<String> set = servercontext.getClients(); 7 Iterator<String> iterator = set.iterator(); 8 while (iterator.hasNext()) { 9 String name = iterator.next(); 10 if (username.equals(name)) { 11 online.add(name + "(本機)"); 12 13 } else { 14 online.add(name); 15 } 16 } 17 18 // 顯示在list中 19 listmodel = new UUListModel(online); 20 count = listmodel.getSize(); 21 list.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "在線用戶:"+count+"人", 22 TitledBorder.LEADING, TitledBorder.TOP, null, new Color(255, 0, 0))); 23 list.setModel(listmodel); 24 docs.insertString(docs.getLength(), servercontext.getInfo() + "\n", attrset); 25 break; 26 }
2.發送消息
(1)客戶端獲取到list中選中的用戶(若不選則為群發),將該選中用戶、自己的用戶名、時間、要發送的信息等內容封裝進對象,設置type為1(發送信息識別碼),將對象傳遞給服務器,在自己的聊天界面添加聊天的內容,隨後清空list表的選中狀態以及發送框的內容(發送按鈕與回車鍵均可發送消息)
1 // 發送按鈕 2 JButton btnNewButton = new JButton("\u53D1\u9001"); 3 btnNewButton.addActionListener(new ActionListener() { 4 public void actionPerformed(ActionEvent arg0) { 5 6 List selected = list.getSelectedValuesList(); 7 String info = textArea_1.getText(); 8 9 if (selected.size() < 1) { 10 // 在客戶端中,容器online中本機的名字後面多加了字符,所以在客戶端不能與hashmap中的key匹配,所以本機收不到本機傳來的信息 11 selected = online; 12 } 13 14 if (info.equals("")) { 15 JOptionPane.showMessageDialog(getContentPane(), "不能發送空信息"); 16 return; 17 } 18 19 ContextDemo clientcontext = new ContextDemo(); 20 clientcontext.setInfo(info); 21 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 22 String time = sdf.format(new Date()); 23 clientcontext.setTime(time); 24 clientcontext.setType(1);// 發信息 25 clientcontext.setName(username); 26 HashSet<String> people = new HashSet<String>(); 27 people.addAll(selected); 28 29 clientcontext.setClients(people); 30 31 // 清空發送頁面 32 textArea_1.setText(""); 33 // 發送界面獲得焦點 34 textArea_1.requestFocus(); 35 // 列表消除選中狀態 36 list.clearSelection(); 37 38 try { 39 out = new ObjectOutputStream(ChatRoom.socket.getOutputStream()); 40 out.writeObject(clientcontext); 41 out.flush(); 42 } catch (IOException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 } 46 47 try { 48 docs.insertString(docs.getLength(), time + " " + "我對"+selected+"說:\n" + info + "\n", attrset); 49 } catch (BadLocationException e) { 50 // TODO Auto-generated catch block 51 e.printStackTrace(); 52 } 53 } 54 });
(2)服務器判斷出為發送消息後,將得到的信息、時間等消息進行封裝,再通過發送給指定用戶的方法將封裝好的對象傳遞給指定的用戶
1 // 發信息 2 case 1: { 3 ContextDemo servercontext = new ContextDemo(); 4 servercontext.setType(1); 5 servercontext.setName(clientcontext.getName()); 6 servercontext.setInfo(clientcontext.getInfo()); 7 servercontext.setTime(clientcontext.getTime()); 8 9 sendtothis(servercontext); 10 break; 11 }
(3)指定的客戶端收到對象後判斷出了是要進行發送消息的操作,解封對象,取得消息等信息,在消息窗口顯示
1 // 發信息 2 case 1: { 3 String info = servercontext.getInfo(); 4 String time = servercontext.getTime(); 5 docs.insertString(docs.getLength(), 6 time + " " + servercontext.getName() + "對我說:\n" + info + "\n", attrset); 7 break; 8 }
3.下線
(1)聊天室頁面添加窗口關閉的監聽事件,在其後彈出對話框確定是否退出,若退出則設置type為2(下線識別碼)、時間等信息封裝進對象發送給服務器
1 // 下線操作 2 this.addWindowListener(new WindowAdapter() { 3 @Override 4 public void windowClosing(WindowEvent e) { 5 6 int result = JOptionPane.showConfirmDialog(getContentPane(),"您確定要離開聊天室"); 7 if (result == 0) { 8 ContextDemo clientcontext = new ContextDemo(); 9 clientcontext.setType(2); 10 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 11 clientcontext.setTime(sdf.format(new Date())); 12 clientcontext.setName(username); 13 14 try { 15 out = new ObjectOutputStream(socket.getOutputStream()); 16 out.writeObject(clientcontext); 17 out.flush(); 18 } catch (IOException e1) { 19 // TODO Auto-generated catch block 20 e1.printStackTrace(); 21 } 22 } 23 } 24 });
(2)服務器判斷為是下線操作後,首先建立服務端對象,設置type為2,用當前用戶傳遞過來的socket傳遞此對象給即將下線的客戶端批准其下線,隨後用下線用戶的用戶名在Hashmap中刪除此用戶,隨後新建另一服務端對象,封裝下線的信息、時間、當前在線用戶名等內容發送給其余所有在線的客戶端,讓他們執行上下線更新操作,並在case的最後用return退出whlie(true)循環,在finally中關閉掉輸入輸出流對象與socket對象,意在此客戶端與服務端的線程關閉
1 // 下線 2 case 2: { 3 // 通知請求下線客戶端,批准下線 4 ContextDemo servercontext1 = new ContextDemo(); 5 servercontext1.setType(2); 6 out = new ObjectOutputStream(socket.getOutputStream()); 7 out.writeObject(servercontext1); 8 out.flush();//需要時間 9 10 // 刷新在線hashmap 11 online.remove(clientcontext.getName()); 12 13 // 通知其他在線用戶,該用戶已下線 14 ContextDemo servercontext2 = new ContextDemo(); 15 servercontext2.setType(0); 16 servercontext2.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + "用戶已下線 "); 17 HashSet<String> set = new HashSet<String>(); 18 set.addAll(online.keySet()); 19 servercontext2.setClients(set); 20 sendtoall(servercontext2); 21 // 退出當前循環,不再監聽該客戶端傳來的信息 22 return; 23 }
(3)
1)即將下線的客戶端接收到對象後,判斷出是執行下線操作,用return退出while(true),並在finally中關閉掉socket與輸入輸出流對象,並用System.exit(0)退出虛擬機斷線
1 // 下線 2 case 2:{ 3 return; 4 }
2)其余在線客戶端接收到對象,判斷是要進行上下線操作,所以執行與上線更新時一樣的操作
1 // 上下線刷新操作 2 case 0: 3 // 重新裝填容器 4 { 5 // 清空容器 6 online.clear(); 7 HashSet<String> set = servercontext.getClients(); 8 Iterator<String> iterator = set.iterator(); 9 while (iterator.hasNext()) { 10 String name = iterator.next(); 11 if (username.equals(name)) { 12 online.add(name + "(本機)"); 13 14 } else { 15 online.add(name); 16 } 17 } 18 19 // 顯示在list中 20 listmodel = new UUListModel(online); 21 count = listmodel.getSize(); 22 list.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "在線用戶:"+count+"人", 23 TitledBorder.LEADING, TitledBorder.TOP, null, new Color(255, 0, 0))); 24 list.setModel(listmodel); 25 docs.insertString(docs.getLength(), servercontext.getInfo() + "\n", attrset); 26 break; 27 }
4.抖窗
(1)客戶端將列表中得到的用戶名封裝進對象,設置type為3,再將時間等信息封裝進對象,將對象發送給服務端
1 btnShakeFrame.addActionListener(new ActionListener() { 2 public void actionPerformed(ActionEvent e) { 3 4 List selected = list.getSelectedValuesList(); 5 6 if (selected.size() < 1) { 7 // 在客戶端中,容器online中本機的名字後面多加了字符,所以在客戶端不能與hashmap中的key匹配,所以本機收不到本機傳來的信息 8 selected = online; 9 } 10 11 ContextDemo clientcontext = new ContextDemo(); 12 clientcontext.setType(3); 13 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 14 String time = sdf.format(new Date()); 15 clientcontext.setTime(time); 16 clientcontext.setName(username); 17 HashSet<String> set = new HashSet<String>(); 18 set.addAll(selected); 19 clientcontext.setClients(set); 20 21 // 列表消除選中狀態 22 list.clearSelection(); 23 24 try { 25 out = new ObjectOutputStream(socket.getOutputStream()); 26 out.writeObject(clientcontext); 27 out.flush(); 28 } catch (IOException e1) { 29 // TODO Auto-generated catch block 30 e1.printStackTrace(); 31 } 32 33 try { 34 docs.insertString(docs.getLength(), time + "您發送了一個屏幕抖動\n", attrset); 35 } catch (BadLocationException e1) { 36 // TODO Auto-generated catch block 37 e1.printStackTrace(); 38 } 39 } 40 });
(2)服務端判斷出是要進行抖窗操作後,封裝有用的信息進對象,並通過發送給指定用戶方法進行發送
1 // 抖窗 2 case 3: { 3 ContextDemo servercontext = new ContextDemo(); 4 servercontext.setType(3); 5 servercontext.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + "對你抖了一下屏 \n"); 6 7 sendtothis(servercontext); 8 break; 9 }
(3)指定的客戶端判斷要進行抖屏,先解封有用的信息進消息顯示窗口,然後再調用封裝好的抖屏方法進行抖屏操作
1 // 抖窗 2 case 3: { 3 String info = servercontext.getInfo(); 4 docs.insertString(docs.getLength(), info, attrset); 5 shakeFrame(); 6 break; 7 }
1 public void shakeFrame() { 2 int x = ChatRoom.this.getX(); 3 int y = ChatRoom.this.getY(); 4 for (int i = 0; i < 20; i++) { 5 if ((i & 1) == 0) { 6 x += 8; 7 y += 8; 8 } else { 9 x -= 8; 10 y -= 8; 11 } 12 ChatRoom.this.setLocation(x, y); 13 try { 14 Thread.sleep(50); 15 } catch (InterruptedException e1) { 16 e1.printStackTrace(); 17 } 18 } 19 }
5.發送文件
(1)客戶端先獲取到想要發送文件給哪個用戶的用戶名,隨後彈出文件選擇框,構建文件的抽象路徑,並得到後綴名,其後通過文件的輸入流將所得到的文件一個字節一個字節的讀入到Arraylist<byte>集合中,將後綴名保存到一個字符串中,將這些與其他有用的信息一起封裝進對象,將對象發送給服務器
1 btnSendFile.addActionListener(new ActionListener() { 2 public void actionPerformed(ActionEvent e) { 3 4 List selected = list.getSelectedValuesList(); 5 if (selected.size() < 1) { 6 JOptionPane.showMessageDialog(getContentPane(), "必須選擇一名用戶"); 7 return; 8 } 9 if (selected.toString().contains(username+"(本機)")) { 10 JOptionPane.showMessageDialog(getContentPane(), "不能向自己發送文件"); 11 return; 12 } 13 14 JFileChooser chooser = new JFileChooser(); 15 chooser.setDialogTitle("選擇文件框"); 16 chooser.showDialog(getContentPane(), "選擇"); 17 18 //判斷是否拿到文件 19 if(chooser.getSelectedFile()!=null){ 20 path = chooser.getSelectedFile().getPath(); 21 file = new File(path); 22 //獲取文件的後綴名 23 int i =file.getName().indexOf("."); 24 last = file.getName().substring(i); 25 26 //判斷文件是否為空 27 if(file.length()==0){ 28 JOptionPane.showMessageDialog(getContentPane(), "文件為空,不能傳送"); 29 return; 30 } 31 } 32 33 ContextDemo clientcontext = new ContextDemo(); 34 //發送文件(基礎工作) 35 clientcontext.setType(4); 36 //保存後綴名 37 clientcontext.setLast(last); 38 clientcontext.setName(username); 39 HashSet<String> set = new HashSet<String>(); 40 set.addAll(selected); 41 clientcontext.setClients(set); 42 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 43 String time = sdf.format(new Date()); 44 clientcontext.setTime(time); 45 46 //發送文件(文件部分操作) 47 list2 = new ArrayList<Byte>(); 48 try { 49 input = new FileInputStream(file); 50 51 int result = -1; 52 53 while((result = input.read()) != -1) 54 { 55 list2.add((byte)result); 56 } 57 58 59 60 } catch (FileNotFoundException e2) { 61 // TODO Auto-generated catch block 62 e2.printStackTrace(); 63 } catch (IOException e1) { 64 // TODO Auto-generated catch block 65 e1.printStackTrace(); 66 }finally { 67 68 try { 69 if(input != null) 70 { 71 input.close(); 72 } 73 } catch (IOException e1) { 74 e1.printStackTrace(); 75 } 76 } 77 78 clientcontext.setList2(list2); 79 80 81 // 列表消除選中狀態 82 list.clearSelection(); 83 84 //發送給服務端 85 try { 86 out = new ObjectOutputStream(socket.getOutputStream()); 87 out.writeObject(clientcontext); 88 out.flush(); 89 } catch (IOException e1) { 90 // TODO Auto-generated catch block 91 e1.printStackTrace(); 92 } 93 94 try { 95 docs.insertString(docs.getLength(), time + "您發送了一個文件\n", attrset); 96 } catch (BadLocationException e1) { 97 // TODO Auto-generated catch block 98 e1.printStackTrace(); 99 } 100 } 101 }); 102
(2)服務端判斷出是要進行文件的發送操作,將所有有用的信息封裝進對象發送給指定的用戶
1 // 發送文件 2 case 4: { 3 ContextDemo servercontext = new ContextDemo(); 4 servercontext.setList2(clientcontext.getList2()); 5 servercontext.setLast(clientcontext.getLast()); 6 servercontext.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + "對你發送了一個文件\n"); 7 servercontext.setType(4); 8 9 sendtothis(servercontext); 10 11 break; 12 }
(3)指定客戶端收到對象後,先將字節集合解封出來,用iterator將字節寫入一個字節數組,再通過緩沖字節流讀入字節,通過解封出來的後綴名構造好新的文件後,通過緩沖字節流寫入文件,並接收到需要的信息顯示在消息窗口中
1 //接收到文件 2 case 4: 3 { 4 ArrayList<Byte> list3 = new ArrayList<Byte>(); 5 list3 = servercontext.getList2(); 6 Iterator<Byte> it = list3.iterator(); 7 byte[] dedao = new byte[10000000]; 8 int i = 0; 9 while(it.hasNext()){ 10 dedao[i] = it.next(); 11 i++; 12 } 13 14 15 ii = new ByteArrayInputStream(dedao); 16 inputStream = new BufferedInputStream(ii,10000); 17 //獲取後綴名 18 String thLast = servercontext.getLast(); 19 output = new FileOutputStream("sourse/dedao"+thLast); 20 outputStream = new BufferedOutputStream(output,10000); 21 22 byte[] b = new byte[10000];//暫存讀取的字節內容 23 int result = -1; 24 while((result = inputStream.read(b)) != -1) 25 { 26 outputStream.write(b, 0, result); 27 } 28 output.flush(); 29 30 31 32 String info = servercontext.getInfo(); 33 docs.insertString(docs.getLength(), info, attrset); 34 break; 35 }