Java網絡----Socket, 多線程實現內網多人聊天及一對一聊天

本文屬於網絡編程,才用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]);  
               } 
            }
        }
    }
}

貼出效果圖:
這裏寫圖片描述
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章