很久以前的一個Demo,這裡服務器只做轉發功能,根據ID地址和端口號來標識身份,群聊和私聊只是簡單實現,
服務器代碼如下:

import java.util.*;
import java.io.*;
import java.net.*;
public class Server extends Thread
{
private static Vector<Socket> vecClient = new Vector<Socket>();
private PrintWriter out;
private BufferedReader in;
private Socket clientsocket;
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(2014); // 創建
System.out.println("啟動服務器! ");
Socket sock;
while (true) {
sock = server.accept(); // 等待客戶請求
Server ser = new Server(sock);
ser.start(); // 啟動
}
}
public Server(Socket socket) {
this.clientsocket = socket;
vecClient.addElement(socket); // 增加客戶線程到數組
try {
// 獲取服務端傳來的字節流好,存到緩沖區
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// printwriter,文本輸出流打印對象的格式化表示形式,只有調用println等,自動刷新即true,強行把緩沖區的數據輸出。
out = new PrintWriter(new OutputStreamWriter(
socket.getOutputStream()), true);
// input、OutputStreamWriter 是字符流通向字節流的橋梁
} catch (IOException e) {
}
}
public void run()
{
try
{
Newclient(); // 向新客戶發出歡迎信息,通知所有在線客戶有新客戶連接了
while(true) // 處理與客戶的交流
{
String msg=in.readLine(); //數據讀取
if(msg.equals("bye")|| msg.equals("拜拜"))//當輸入拜拜或bye時候退出
{
Xiaxian();
in.close(); // 關閉輸入流
clientsocket.close(); // 關閉socket
break;
}
else if(msg.indexOf("@")==0&&msg.indexOf(" ")>0){
int end=msg.indexOf(" ");
String findAddr=msg.substring(1,end);
if(vecClient.isEmpty() == false) //判斷為空
{
for(int i=0;i<vecClient.size();i++)
{
Socket socket = vecClient.get(i);
String addr = socket.getInetAddress().toString().replace("/", "") + ":"
+ socket.getPort();
if(findAddr.equals(addr)){
String addr2 = clientsocket.getInetAddress().toString().replace("/", "") + ":"
+ clientsocket.getPort();
//elementAt返回指定索引處的組件,而get返回列表中指定位置處的元素
PrintWriter pw = new PrintWriter(new OutputStreamWriter(vecClient.get(i).getOutputStream()),true);
pw.println("大神"+addr2+" 對你 說: "+msg.substring(end));
}
}
}
}
// 否則將接收到的信息向所有在線客戶發出去
else
{
if(vecClient.isEmpty() == false)
for(int i=0;i<vecClient.size();i++)
{
//elementAt返回指定索引處的組件,而get返回列表中指定位置處的元素
PrintWriter pw = new PrintWriter(new OutputStreamWriter(vecClient.get(i).getOutputStream()),true);
pw.println("大神"+clientsocket.getInetAddress().toString()+":"+clientsocket.getPort()+" 說: "+msg);
}
}
}
}
catch(IOException e)
{ }
}
public void Newclient() throws IOException // 新來的,用此函數
{
String addr = clientsocket.getInetAddress().toString() + ":"
+ clientsocket.getPort();
out.println("歡迎:" + addr+"加入! ");
try {
if (vecClient.isEmpty() == false)
for (int i = 0; i < vecClient.size(); i++)
{
Socket socket = vecClient.get(i);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(
socket.getOutputStream()), true);
String addr2 = socket.getInetAddress().toString() + ":"
+ socket.getPort();
if (addr.equals(addr2)) {
pw.println("歡迎加入聊天,私聊請用@ip:port 內容");
} else {
pw.println("新成員:"
+ clientsocket.getInetAddress().toString()
+ ":" + clientsocket.getPort() + " 嗨起來吧!");
}
}
} catch (IOException e) {
}
}
public void Xiaxian() throws IOException // 下線方法
{
out.println("再見,連接關閉!");
if (vecClient.isEmpty() == false)
for (int i = 0; i < vecClient.size(); i++) {
PrintWriter pw = new PrintWriter(new OutputStreamWriter(vecClient
.get(i).getOutputStream()), true);
pw.println("--" + clientsocket.getInetAddress().toString()
+ ":" + clientsocket.getPort() + " 已經下線");
}
vecClient.remove(clientsocket);
}
}
View Code
客服端,可在本地命令運行多個測試,私聊格式:@ip:port(這裡必須有空格)內容,原理如下:

import java.net.*;
import java.io.*;
import java.util.*;
class Client
{
public static void main(String[] args)
{
try
{
Socket socket=new Socket("localhost",2014);
ClientSend send=new ClientSend(socket); // 創建發送線程
ClientReceive receive=new ClientReceive(socket); // 創建接收線程
send.start(); // 啟動發送線程
receive.start(); // 啟動接收線程
}
catch(Exception e)
{
System.out.println("服務器沒有開啟呢!");
e.printStackTrace();
}
}
}
class ClientSend extends Thread
{
private Socket socket;
private PrintWriter out;
public ClientSend(Socket socket)
{
this.socket=socket;
try
{
out=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
//返回一個服務器與客戶端的輸出流,true強行把緩沖區的數據輸出
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void run() // 發送信息到服務器
{
String msg;
Scanner input=new Scanner(System.in);//輸入
msg = input.nextLine(); //nextLine方法返回的是回車之前的所有字符
while(true)
{
//用equalsIgnoreCase可忽略大小寫
if(msg.equals("bye") || msg.equals("拜拜"))
{
out.println(msg);
break;
}
out.println(msg);
msg = input.nextLine();
}
}
}
class ClientReceive extends Thread //接收
{
private Socket socket;
private BufferedReader in;
public ClientReceive(Socket socket)
{
this.socket= socket;
try
{
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void run() // 接收服務器發來的信息
{
try
{
String msg=in.readLine();
while(msg.equals("bye") == false)
{
System.out.println(msg);
msg=in.readLine();
}
in.close();
socket.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
View Code