Java網路編程,java網路編程pdf
最近比較閑,一直在抽空回顧一些Java方面的技術應用。
今天沒什麼事做,基於UDP協議,寫了一個非常簡單的聊天室程式。
現在的工作,很少用到socket,也算是對Java網路編程方面的一個簡單回憶。
先看一下效果:
實現的效果可以說是非常非常簡單,但還是可以簡單的看到一個實現原理。
“聊天室001”的使用者,小紅和小綠相互聊了兩句,“聊天室002”的小黑無人理會,在一旁寂寞著。
看一下代碼實現:
1、首先是Message Service器的實現,功能很簡單:
- 將用戶端的資訊(進入了哪一個聊天室等)進行登記;
- 構造UDP協議通訊端對象,接受各個用戶端發送的訊息;
- 解析訊息內容,將聊天資訊推送回對應聊天室的各個用戶端;
package com.tsr.simplechat.receive_server;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketException;import java.util.ArrayList;import java.util.HashMap;import com.google.gson.Gson;import com.tsr.simplechat.bean.MessageEntity;import com.tsr.simplechat.client.ChatClient;//聊天伺服器public class ChatServer extends Thread {// 程式佔用連接埠號碼private static final int PORT = 10000;// 訊息接受通訊端對象private static DatagramSocket server = null;// 字典對象(Key:聊天室ID,Value:該聊天室下的用戶端使用者集合);private static HashMap<String, ArrayList<ChatClient>> groups = new HashMap<String, ArrayList<ChatClient>>();// 構造器public ChatServer() {try {// 訊息接受通訊端對象的構造初始化server = new DatagramSocket(PORT);} catch (SocketException e) {e.printStackTrace();}}// 註冊聊天室新登入使用者public static void logInGroup(String groupID, ChatClient client) {// 通過聊天室ID,擷取該聊天室的所有線上使用者ArrayList<ChatClient> clients = groups.get(groupID);if (clients == null) {clients = new ArrayList<ChatClient>();}// 將此次進入聊天室的使用者登記clients.add(client);// 更新聊天室資訊groups.put(groupID, clients);}// 迴圈接收訊息@Overridepublic void run() {while (true) {receiveMessage();}}private void receiveMessage() {// UDP資料包byte[] buf = new byte[1024];DatagramPacket packet = new DatagramPacket(buf, buf.length);while (true) {try {// 接受資料包server.receive(packet);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 解析資料包,擷取聊天資訊String content = new String(packet.getData(), 0, packet.getLength());// 通過第三方包解析json資料Gson gson = new Gson();MessageEntity me = gson.fromJson(content, MessageEntity.class);// 解析訊息內容,通過聊天室ID,擷取該聊天室的所有線上使用者ArrayList<ChatClient> clients = groups.get(me.getGroupId());// 將接收到的訊息推送回該聊天室的各個使用者for (ChatClient client : clients) {client.pushBackMessage(me);}}}}
2、用戶端程式,依然很簡單:
- 簡單的定義用戶端聊天室介面。
- 構造訊息發送通訊端對象。
- 擷取聊天資訊框的內容,發送到伺服器。
package com.tsr.simplechat.client;import java.awt.Button;import java.awt.Event;import java.awt.Frame;import java.awt.TextArea;import java.awt.TextField;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;import java.net.UnknownHostException;import com.tsr.simplechat.bean.MessageEntity;import com.tsr.simplechat.receive_server.ChatServer;//用戶端程式public class ChatClient extends Frame {private static final long serialVersionUID = 1L;// 聊天室IDprivate String groupID;// 用戶端使用者名稱private String clientName;// 用戶端訊息發送服務通訊端private DatagramSocket msg_send;// 服務連接埠private final int PORT = 10000;// 伺服器IP地址private InetAddress ip;// 用戶端控制項TextField tf = new TextField(20);TextArea ta = new TextArea();Button send = new Button("send");// 用戶端構造器public ChatClient(String groupID, String clientName) {super("聊天室:" + groupID + "/" + clientName);this.clientName = clientName;this.groupID = groupID;// 設定用戶端介面樣式add("North", tf);add("Center", ta);add("South", send);setSize(250, 250);show();// 聊天相關伺服器初始化init();// 監視器addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {// 關閉訊息發送服務msg_send.close();// 關閉用戶端程式dispose();System.exit(0);}});}// 聊天相關伺服器初始化private void init() {// 註冊目前使用者及所在聊天室資訊註冊到伺服器ChatServer.logInGroup(groupID, this);try {// 初始化訊息發送通訊端對象msg_send = new DatagramSocket();// 指定Message Service器try {ip = InetAddress.getByName("127.0.0.1");} catch (UnknownHostException e) {System.out.println("未知的主機異常..");}} catch (SocketException e) {System.out.println("通訊端串連異常..");}}// 訊息發送按鈕時間監聽public boolean action(Event evt, Object arg) {if (evt.target.equals(send)) {try {// 擷取輸入內容String content = tf.getText();// 發送訊息send_message(content);// 清空聊天框tf.setText(null);} catch (Exception ioe) {System.out.print(ioe.getMessage());}}return true;}// 訊息發送private void send_message(String content) {// 訊息格式化(json格式)String message = messageFormat(content);// 將訊息封裝成UDP資料包byte[] buf = message.getBytes();DatagramPacket packet = new DatagramPacket(buf, buf.length, ip, PORT);try {// 通過UDP協議發送訊息msg_send.send(packet);} catch (IOException e) {System.out.println("IO異常..");}}// 訊息格式化private String messageFormat(String content) {StringBuffer buffer = new StringBuffer();buffer.append("{\"groupId\":").append("\"").append(groupID).append("\",");buffer.append("\"userName\":\"").append(clientName).append("\",");buffer.append("\"text\":\"").append(content).append("\"}");return buffer.toString();}// 從伺服器擷取當前聊天室最新訊息(回調..)public void pushBackMessage(MessageEntity me) {ta.append(me.getUserName() + ":" + me.getText());ta.append("\n");}}
3、訊息實體類
主要就是用於將訊息封裝成對象,包含:聊天室ID、訊息寄件者暱稱,訊息內容。使用json格式解析。
package com.tsr.simplechat.bean;//訊息實體public class MessageEntity {private String groupId;private String userName;private String text;public String getGroupId() {return groupId;}public void setGroupId(String groupId) {this.groupId = groupId;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getText() {return text;}public void setText(String text) {this.text = text;}}
4、OK,到了這裡就基本搞定了,建立一個測試類別。
- 開啟Message Service器。
- 開啟三個用戶端,其中兩個進入“聊天室001”,另一個進入“聊天室002”。
import com.tsr.simplechat.client.ChatClient;import com.tsr.simplechat.receive_server.ChatServer;public class Test {public static void main(String[] args) {ChatServer r = new ChatServer();r.start();ChatClient c1 = new ChatClient("001", "小紅");ChatClient c2 = new ChatClient("001", "小綠");ChatClient c3 = new ChatClient("002", "小黑");}}
源碼