1. 程式人生 > >socket實現人多聊天與Java代碼加載過程

socket實現人多聊天與Java代碼加載過程

exc add 數據 開啟 客戶 字節 src 阿裏 構造方法

第一部分是java代碼加載過程

關於java代碼加載過程,今天調試了阿裏巴巴一份代碼,如下:

/**
 * 加載方法不等於執行方法,初始化變量則會賦值
 *             類加載順序應為 加載靜態方法-初始化靜態變量-執行靜態代碼塊
 *             實例化時 先加載非靜態方法-實例化非靜態變量-執行構造代碼塊-執行構造函數
 * @author panteng
 *
 */
public class StaticTest {
    /**第一個加載*/
    public static int k = 0;
    /**第二個加載,因為是new一個實例,
     * 首先初始化j 打印出  1:j i=0 n=0
     * 執行構造塊     打印出  2:構造快 i=1 n=1
     * 執行構造方法 打印出  3:t1 i=2 n=2
     * 實例化完成
     */
    public static StaticTest t1 = new StaticTest("t1");
    /**第三個加載 過程同上
     * 首先初始化j 打印出  4:j i=3 n=3
     * 執行構造塊     打印出  5:構造快 i=4 n=4
     * 執行構造方法 打印出  6:t2 i=5 n=5
     */
    public static StaticTest t2 = new StaticTest("t2");
    /**第四個加載
     * 打印出  7:i i=6 n=6
     */
    public static int i = print("i");
    /**
     * 第五個加載
     */
    public static int n = 99;
    /**
     * 此變量在類加載的時候並不初始化,在實例化類的時候初始化
     */
    public int j = print("j");
     
    {
        print("構造快");
    }
    /**
     * 第六個加載 此時,n已經被初始化  所以打印出
     * 8:靜態塊 i=7 n=99
     */
    static{
        print("靜態塊");
    }
    //-----------以上屬於類加載---------------------
    /**
     * 實例化過程:
     *         首先加載非靜態方法集;
     *         初始化非靜態變量:9:j i=8 n=100
     *         執行構造塊:10:構造快 i=9 n=101
     *         執行構造方法:11:init i=10 n=102
     * 實例化完成
     */
    
    /**
     * 執行構造函數  實例化完成
     * @param str
     */
    public StaticTest(String str) {
        System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
        ++n;
        ++i;
    }
    /**
     * 這個應該是最先加載 但是,加載不等於執行
     * 因為如果不加載此函數,靜態變量是無法初始化的
     * @param str
     * @return
     */
    public static int print(String str) {
        System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
        ++i;
        return ++n;
    }
    
    public static void main(String[] args) {
        StaticTest t = new StaticTest("init");
    }
 
}

  首先加載類,然後實例化:

          類加載過程:
                  首先加載所有的靜態方法,但不執行;
                  然後按照靜態變量的順序開始初始化
                  靜態變量初始化完畢後執行靜態構造塊(不執行構造塊)
                  此時類加載完畢
          實例化過程:
                  加載非靜態方法
                  初始化非靜態變量
                  執行構造代碼塊
                  執行構造函數
                  此時實例化完畢

第二部分是socket實現多對多的群聊
代碼部分跟昨天實現一對一的變化主要在服務器這端,在服務端使用List集合來保存一組socket,每當有一個客戶端向服務端發送socket時,
都會將這個socket加入到數組列表中,然後開啟一個新的線程來為這個客戶端群發消息。介於昨天使用BufferInputStream的readLine方法出
現了換行問題,今天直接使用字節來傳輸消息,InputStream的方法read(byte[] b)方法可以將讀到的數據傳到字節數組中,並且返回字節
數組的長度,int len = in.read(b),然後將字節數組轉換成字符串,String str = new String(b,0,len);輸出的時候也不一定使用
PrintWriter方法,可以直接使用socket.getOutputStream()返回的OutputStream來發送數據,註意前者PrintWriter是使用print,後者
OutputStream是使用write方法。
e.g: out.print(str);
e.g: out.write(str.getByte());
傳輸方法跟昨天的有所不同,以及服務端的改動,我還是講客戶端和服務端的代碼發一遍。
客戶端:
import java.net.*;
import java.io.*;
import java.util.Scanner;

public class Client {

    public static String sg ;//客戶端用戶名

    public Client() {
        try {

            Socket socket = new Socket("127.0.0.1", 4800);
            System.out.println("客戶端已經開啟----");
            System.out.println("請取您的用戶名");
            Scanner scanner = new Scanner(System.in);
            sg=scanner.next();
            new Thread(new Output(socket)).start();
            new Thread(new Input(socket)).start();

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

    class Input implements Runnable {
        Socket socket;

        public Input(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            while (true) {
                try {
                    InputStream in = socket.getInputStream();
                    byte[] b = new byte[1024];
                    int len = in.read(b);

                    String str = new String(b, 0, len);
                    System.out.println(str);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

//輸出信息到服務端
    class Output implements Runnable {
        Socket socket;

        public Output(Socket socket) {
            this.socket = socket;
        }

        public void run() {

            try {
                Scanner scanner = new Scanner(System.in);
                while(true) {
                    OutputStream out = socket.getOutputStream();
                    String str = sg+":"+scanner.next();
                    out.write(str.getBytes());
                }

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

    public static void main(String[] args) {
        new Client();
    }
}

  服務端代碼:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {

    List<Socket> list = new ArrayList<Socket>();//將收到客戶端的socket添加到數組列表

    public Server() {
        try {
            ServerSocket serverSocket = new ServerSocket(4800);
            System.out.println("服務端正在等待客戶端請求......");

            while (true) {
                Socket socket = serverSocket.accept();
                new Thread(new Output(socket, list)).start();
                list.add(socket);
            }

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

    class Output implements Runnable {
        Socket socket;
        List<Socket> list;

        public Output(Socket socket, List<Socket> list) {
            this.socket = socket;
            this.list = list;
        }

        public void run() {
            try {
                while (true) {
                    InputStream in = socket.getInputStream();
                    byte[] b = new byte[1024];
                    int len = in.read(b);
                    String str = new String(b,0,len);
                    list.remove(socket);//每次群發消息不發給發送給服務器的一方客戶端
                    for (Socket s:list){
                        OutputStream out = s.getOutputStream();
                        out.write(str.getBytes());
                    }
                    list.add(socket);
                }

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


    public static void main(String[] args) {
        new Server();
    }
}

  以及今天無意間看到了關於線程的生命周期,權當復習一下:

技術分享圖片

總結
今天不是第一次使用socket了,遇到的問題不像昨天那麽多,但是還是有很大一部分的問題,socket編程,關於
TCP與UDP方面的通訊,現在還沒有進行嘗試,還有同一個局域網和不同網絡方面的問題,學習還是需要一步步的來,不能
一口吃撐胖子,今天也挺有收獲的,了解了java加載類方面的知識,感覺在類實例化前,就先初始化了靜態變量和方法,
在以後的學習中可能會有用;實現了類似QQ群聊的功能,如果想多寫點,我覺得既然有群聊,在群聊的基礎上我還可以寫個
聊天室裏一個用戶對另一額用戶的私聊,私聊方面現在思路基本就是,當客戶端輸入私聊+ID名,剩下的基本就是跟一對一
一樣的。

socket實現人多聊天與Java代碼加載過程