天天看點

使用Socket實作最簡單的聊天功能

平時開發中會經常接觸到Socket,其使用也不複雜,在阻塞Socket中,主要是了解什麼操作會導緻阻塞。serverSocket的accept方法會一直阻塞直到有用戶端Socket進入,處理時最好是另開一個線程給它。

把聊天系統簡單化,一個伺服器是必需的,下面稱之為A,用來傳輸兩個進行聊天的用戶端之間的消息,下面稱為B和C。B需要一個标志位,用于檢查是否剛登入,若是,自動發送自己的ID和消息給A,告訴A我已上線,然後A中需要有一個客戶清單用來儲存線上的客戶ID。接下來B發送消息給C前,要把C的ID也發送給A,這樣才能進行B和C之間的正常通信。當然,A還要先根據C的ID檢查客戶清單中是否有C,已确定C是否線上上;若C不線上上就要告訴B,若在,B和C通信建立,可以開始聊天了。

===========================================================傳說中的分界線=============================================================

伺服器代碼:

package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class ServerChat {

	private static ServerSocket server;
	private static volatile HashMap
   
     userQueue = new HashMap
    
     ();

	public ServerChat(int port, int backlog) {
		try {
			server = new ServerSocket(port);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 使用者聊天的核心方法
	 */
	private static void processChat() {

		// boolean shutdown = false;
		// String received = null;
		System.out.println("等待使用者接入。。。");
		try {

			while (true) {
				Socket client = server.accept();
				System.out.println("已有使用者接入,等待資訊。。。");

				new Thread(new Runnable() {

					TransferMsgThread tranUserInfo = new TransferMsgThread(
							client);
					String send = null;
					boolean firstTime = true;
					String userID = null;
					String friendID = null;

					@Override
					public void run() {
						System.out.println("即将進入while循環。。。");

						while (true) {

							send = tranUserInfo.sendMessage();
							// 客戶上線時,背景主動發送消息通知伺服器客戶已上線

							if (send != null) {
								System.out.println("info content :" + send);

								if (firstTime
										&& send.substring(send.indexOf(':') + 1)
												.equalsIgnoreCase("I am onLine")) {
									userID = send.substring(0,
											send.indexOf(":"));
									send = send.substring(send.indexOf(":") + 1);
									
									// 将線上使用者添加進表中
									if (userQueue.size() == 0
											|| userQueue.get(userID) == null) {
										userQueue.put(userID, client);
									}
									
									firstTime = false;
									System.out.println("userQueue get "
											+ userQueue.get(userID));

								} else {

									friendID = send.substring(0,
											send.indexOf(":"));
									System.out.println("friendID == "
											+ friendID);

									send = send.substring(send.indexOf(":") + 1);

									Socket friend = (Socket) userQueue
											.get(friendID);
									if (friend == null) {
										tranUserInfo.receiveMessage("對方未上線!");
									} else {
										if (send.equals("shutdown")) {
											// shutdown = true;
											// break;
										}
										TransferMsgThread tranFriendInfo = new TransferMsgThread(
												friend);
										tranFriendInfo.receiveMessage(userID
												+ ": " + send);
									}
								}

							} else {
								if (firstTime) {
									firstTime = false;
									System.out.println("message is null !");
								}
							}

						}

					}
				}).start();

			}
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		// closeConnect();
	}

	protected static void closeConnect() {
		try {
			server.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {

		new ServerChat(8899, 100).processChat();
	}

}

    
   
           
package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TransferMsgThread {
	private volatile String message;

	private Socket client;

	public TransferMsgThread(Socket client) {
		this.client = client;
	}

	public String sendMessage() {

		try {
			message = sendMessageToOtherClient(client);

		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("message == " + message);
		return message;
	}

	public void receiveMessage(String msg) {

		try {
			getMessageFormOtherClient(client, msg);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	protected void getMessageFormOtherClient(Socket client, String msg)
			throws IOException {
		BufferedWriter writer;
		writer = new BufferedWriter(new OutputStreamWriter(
				client.getOutputStream(), "UTF-8"));
		writer.write(msg + "EOF");
		writer.newLine();
		writer.flush();
	}

	protected static String sendMessageToOtherClient(Socket client)
			throws IOException {
		BufferedReader reader;
		reader = new BufferedReader(new InputStreamReader(
				client.getInputStream(), "UTF-8"));
		StringBuffer msg = new StringBuffer();
		String tmp = null;
		int index = -1;
		
		while ((tmp = reader.readLine()) != null) {
			if ((index = tmp.indexOf("EOF")) != -1) {
				tmp = tmp.substring(0, index);
				msg.append(tmp);
				System.out.println("break out while!");
				break;
			}
			msg.append(tmp);
		}

		return msg.toString();
	}
}
           

用戶端代碼:

package Test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

public class Client {

	private String host;;
	private int port;;
	private Socket client;

	public Client() {
		this( "127.0.0.1", 8899);
	}

	public Client(String host, int port) {
		this.host = host;
		this.port = port;
		try {
			client = new Socket(host, port);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void writeInfo(String info) {
		BufferedWriter writer = null;
		try {
			writer = new BufferedWriter( new OutputStreamWriter(client.getOutputStream(),
					"UTF-8"));
			writer.write(info);
			writer.newLine();
			writer.flush();

		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
//		finally {
//			if (writer != null) {
//				try {
//					writer.close();
//				} catch (IOException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
//			}
//		}
	}

	public String readInfo() throws SocketTimeoutException{
		
		String info = null;
		BufferedReader br = null;
		
		try {
			br = new BufferedReader(new InputStreamReader(
					client.getInputStream(), "UTF-8"));
			
//			client.setSoTimeout(5 * 1000);
			
			StringBuffer sb = new StringBuffer();
			String temp;
			int index;
			
			while((temp = br.readLine()) != null) {
				if((index = temp.indexOf("EOF")) != -1) {
					sb.append(temp.substring(0, index));
					break;
				}
				sb.append(temp);
			}
			
			info = sb.toString();
			
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
//		finally {
//			if(br != null) {
//				try {
//					br.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//				
//			}
//		}

		return info;
	}
	
	public void clientDown() {
		if(client != null) {
			try {
				client.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
           
package Test;

import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;


public class MainTest {
	
	private static Client client;
	private static SimpleDateFormat format;
	
	
	public static void main(String[] args) {
		
		
		System.out.println("start client");
		
		Scanner input = new Scanner(System.in);
		String line = null;
		
		System.out.println("請輸入你的ID:");
		 line = input.nextLine();
		client = new Client();
		client.writeInfo(line + ":I am onLine" + "EOF");
		
		new Thread() {
			public void run() {
				while(true) {
					String info;
					try {
						info = client.readInfo();
						if(info != null) {
							System.out.println(info);
						}
					} catch (SocketTimeoutException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}
			};
		}.start();
		
		System.out.println("請輸入你朋友的ID:");
		String id = input.nextLine();
		
		System.out.println("聊天開始:");
		
		new Thread() {
			public void run() {
				while(true) {
					String line = input.nextLine();
					client.writeInfo(id + ":" + line + "EOF");
					if(line.equalsIgnoreCase("shutdown")) {
						break;
					}
				}
			};
		}.start();
		
		
//		Timer timer = new Timer(true);
//		
//		TimerTask task = new TimerTask() {
//
//			public void run() {
//				plane();
//			}
//			
//		};
//		
//		timer.schedule(task, 2 * 1000, 5 * 1000);
//		
//		try {
//			Thread.sleep(50 * 1000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
	}
	
	public static void plane() {
		System.out.println("client plane starting");
		
		format = new SimpleDateFormat(
				"yy-MM-dd HH:mm:ss");
		
		client = new Client();
		client.writeInfo(format.format(new Date()));
		
		try {
			System.out.println("info show by client,form server"
					+ client.readInfo());
		} catch (SocketTimeoutException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
//		client.clientDown();
		
	System.out.println("client real in the end!");
}
}

           

繼續閱讀