本文屬於網絡編程,才用Socket+多線程編程,實現使用控制檯進行多人互動聊天,以及一對一互動聊天,
服務器端代碼:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.ArrayList;
public class SimpleServer {
//用於保存當前連接的用戶
public static ArrayList<Socket> socketList=new ArrayList<Socket>();
/**
* 服務器主函數
* @param args
* @throws Exception
*/
public static void main(String[] args)throws Exception {
//創建一個serverSocket,用於監聽客戶端Socket的連接請求
ServerSocket serverSocket = new ServerSocket(10002);//10002爲此服務器的端口號
System.out.println("服務啓動.....");
//採用循環不斷接收來自客戶端的請求
while (true) {
//每當接收到客戶端的請求時,服務器端也對應產生一個Socket
Socket socket = serverSocket.accept();
System.out.println("服務連接....");
// 把連接的客戶端加入到list列表中
socketList.add(socket);
System.out.println("當前有:"+socketList.size()+"個客戶端連接");
//啓動一個新的線程
//任務線程,每個連接用都有一個屬於自己專用的任務線程
//這個線程內會處理信息的發送和響應
new MyThread(socket,socketList).start();
}
}
}
class MyThread extends Thread {
//一個雙向的通信連接實現數據的交換,這個連接的一端稱爲一個socket。建立網絡通信連接至少要一對端口號(socket)
Socket client;
ArrayList<Socket> clients;
BufferedReader br;
public MyThread(Socket client,ArrayList<Socket> clients)throws Exception {
super();
this.client = client;
this.clients = clients;
br = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
}
//把接收到的消息發送給各客戶端
public void run() {
try {
String content=null;
while(true){
//從某個客戶端讀取信息
if((content=br.readLine())!=null) {
for(Socket socket:clients){
if(client!=socket){
//把讀取到的消息發送給各個客戶端
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
pw.println(content);
}
}
content = URLDecoder.decode(content, "UTF-8");
System.out.println(content);
}
}
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客戶端代碼:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URLDecoder;
public class Client {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//創建連接到本機,端口爲10002的socket
System.out.println("123");
Socket client = new Socket("192.168.1.49", 10002);
new MyThread(client).start();
InputStream is = client.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while (true) {
String msg = br.readLine();
//對收到的信息進行解碼
msg=URLDecoder.decode(msg, "UTF-8");
System.out.println(msg);
}
}
}
客戶端線程方法:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URLEncoder;
import java.net.UnknownHostException;
public class MyThread extends Thread {
Socket client;
//消息發送人名稱,即本機的名稱
String hostName = "";
public MyThread(Socket client) {
super();
this.client = client;
try {
InetAddress addr = InetAddress.getLocalHost();
hostName =addr.getHostName().toString(); //獲取本機計算機名稱
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public void run() {
// 發出消息
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
PrintWriter pw = new PrintWriter(client.getOutputStream(), true);
// 把輸入的內容輸出到socket
while (true) {
String msg = br.readLine();
//對發出的消息進行編碼
msg = URLEncoder.encode(hostName + "說:"+ msg, "UTF-8");
pw.println(msg);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
至此簡單的多人聊天已經實現
運行服務器,再運行兩臺客戶機,進行消息發送,通過服務器發送其他客戶機,
效果如下:
服務器打印內容:
服務啓動…..
服務連接….
當前有:1個客戶端連接
服務連接….
當前有:2個客戶端連接
Vip_HYP-PC說:我是客戶A
Vip_HYP-PC說:我是客戶B
客戶機B打印內容:
Vip_HYP-PC說:我是客戶A
我是客戶B
當然這樣的效果過於簡陋,,比如我們可以讓客戶機來查看有幾個用戶?以及對某個特定的用戶進行消息發送?想到這些,那就在服務器端先加上業務邏輯把.
先進行客戶端改變:
刪除hostName 定義實現,改爲電腦ip標識:
//消息發送人名稱
String userName = "";
//消息發送人IP地址,身份的唯一標識
String hostIP="";
MyThread方法修改
public MyThread(Socket client) {
super();
this.client = client;
try {
InetAddress addr = InetAddress.getLocalHost();
hostIP=addr.getHostAddress().toString();//獲取本機的計算機IP
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
run方法增加username判斷
String msg = br.readLine();
//剛登錄,進行用戶名填寫
if(userName.equals("")){
//對發出的消息進行編碼
msg = URLEncoder.encode(hostIP+"__"+ msg, "UTF-8");//添加用戶IP做唯一標識
pw.println(msg);
}else{
//添加用戶IP做唯一標識
msg = URLEncoder.encode(hostIP+"__"+userName + "__說:"+ msg, "UTF-8");
pw.println(msg);
}
接下來是服務器端代碼修改:
首先mian方法中,對每次連接用戶發送一個消息,進行用戶名註冊
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
pw.println("請輸入您的用戶名,進行聊天");
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//創建用戶名
String content = "";
if((content=br.readLine())!=null) {
//以__拆分消息內容,ip,username
content = URLDecoder.decode(content, "UTF-8");
String[] contents = content.split("__");
userNameMap.put(contents[0], contents[1]);
}
重點到了,對獲取到的消息進行判斷執行:
if((content=br.readLine())!=null) {
content = URLDecoder.decode(content, "UTF-8");
//以__拆分消息內容,ip,username+內容
String[] contents = content.split("__");
if(contents.length==3){
if(contents[2].equals("說:1")){//查看所有登錄用戶
for(Socket socket:clients){
if(client!=socket){//不是自身
PrintWriter pw = new PrintWriter(client.getOutputStream(), true);
pw.println("用戶名:"+userNameMap.get(socket.getInetAddress().toString())+",ip地址:"+socket.getInetAddress());
}
}
}
}
if(contents[2].equals("說:2")){//進行指定人聊天
//進行消息指定發送
}
if(contents[2].equals("說:e")){//退出指定人聊天
//銷燬兩用戶的一對一關聯,未實現
}else{
for(Socket socket:clients){
if(client!=socket){
//把讀取到的消息發送給各個客戶端
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
pw.println(contents[1]+'['+contents[0]+']'+contents[2]);
}
}
}
}
}
貼出效果圖: