簡體   English   中英

Java中的服務器程序,並傳遞對Socket對象的引用

[英]Server program in Java and passing a reference to a Socket object

我正在用Java寫一個多線程程序,在這里我創建了一個單獨的線程來處理每個新的客戶端連接。 我有:

Socket s;


while(true)
{
    s = server.accept();
    ClientHandler ch = new ClientHandler(s);
    Thread servingThread = new Thread(ch);
    servingThread.start();
}

在ClientHandler線程中,我有:

public class ClientHandler implements Runnable
{
    private Socket s;

public ClientHandler(Socket _Socket, boolean _accepted, BaseStation _bs)
{
    this.s = _Socket;
}

如果在Java中我無法傳遞對象,而只能傳遞對其的引用,那么只要server接受新連接,這都不會對ClientHandler內的s實例造成問題嗎? 它也不會在ClientHandler內部更改並破壞它嗎? 如果是這樣,正確的方法是什么?

請參閱Java是“按引用傳遞”還是“按值傳遞”? 解釋。

將新的Socket實例傳遞給新的ClientHandler實例很好,因為每個ClientHandler都有自己的Socket更改本地變量s的值不會影響ClientHandler內部的Socket實例的副本。

這樣的東西會導致一個問題:

ClientHandler ch = new ClientHandler(s);
Thread servingThread = new Thread(ch);
servingThread.start();

s.someMethod(); // close, read etc.

因為ch.ss都指向同一個基礎Socket對象實例。

順便說一句:在while循環中分離出一個新的線程可能是不好的,除非您確定這些線程將終止。 使用ThreadPool可能更好。

您的擔心是正確的,因為Socket對象(與Java中的其他任何對象一樣)都是通過引用傳遞的,因此有可能被不同的模塊或不同的線程引用,從而導致不可預測的行為。

但是,如果您的程序沒有問題。 原因是:每當服務器接受新連接時,它將創建一個新的 Socket對象,然后將其傳遞給ClientHandler實例。 因此,來自客戶端的每個新連接都將由一個獨立的ClientHandler實例提供服務,因此不必擔心Socket對象的爭用條件。 因此,您現在是安全的。

作為反例,如果您決定創建兩個ClientHandler線程以從同一 Socket對象中讀取,就像這樣...

s = server.accept();
ClientHandler ch = new ClientHandler(s);
ClientHandler ch2 = new ClientHandler(s);
new Thread(ch).start();
new Thread(ch2).start();

......那么你可能會遇到麻煩因為有兩個ClientHandler旨意得到相同的參照相同 Socket對象,如果都試圖從同一個套接字讀取他們將各獲得只有一半的數據。 例如,如果您收到字符串"hello" ,則可能會以ch讀取為"hel"ch2讀取為"lo"或任何其他組合而結束。

這有點令人困惑,但是您的代碼應該按所示工作。 Java首先通過值傳遞,然后通過引用傳遞。 IE瀏覽器,你不是在一個指針傳遞給你的“ Socket s ”,但“實際價值s ”當時你傳遞它。

為了簡化事情並消除混亂,我只刪除了您的“ Socket s; ”的前向聲明,並使循環的第一行成為“ Socket s = server.accept(); ”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM