Java多線程 Socket使用


點我跳過黑哥的卑鄙廣告行為,進入正文。

 

Java多線程系列更新中~

  正式篇:

  1. Java多線程(一) 什么是線程
  2. Java多線程(二)關於多線程的CPU密集型和IO密集型這件事
  3. Java多線程(三)如何創建線程
  4. Java多線程(四)java中的Sleep方法
  5. Java多線程(五)線程的生命周期

  番外篇(神TM番外篇):

  1. Java 過一下基礎
  2. 轉載:java中Thread.sleep()函數使用
  3. Java多線程 Socket使用

 

Socket是客戶端和服務器端交流的端點。通過它可以實現客戶端和服務器端的通信。順着這篇文章操作下來,你應該會對Socket編程有比較系統的了解。注意,跟着敲代碼,有什么不懂而我又沒提到的地方,隨時百度,不要積累誤差。

客戶端編程

Socket是有連接的,所以雙方建立通信,需要知道彼此的網絡位置(IP和端口)。

創建Socket對象:

Socket socket = new Socket("127.0.0.1",8852);
  • 第一個參數:服務器的IP地址(這里用的是本機地址)
  • 第二個參數:TCP端口號,其中0~1023是系統保留端口。

為什么需要端口號?例如你想要去找你的暗戀對象告白,你知道她的學校地址(IP地址),但是一個學校不會只有你暗戀對象一個人(一個主機不會只進行一個任務),你需要知道她的宿舍號(端口號),這樣才能方便告白。

使用本機既做客戶端,又做服務器是個什么情況?就是你和你暗戀對象在同一個學校,這沒什么區別,你仍然需要她的宿舍號(端口號)才能找到她告白(客戶端和服務前通信)。

初始版本代碼

public class MyClient {
    public static void main(String[] args) throws Exception{
    Socket socket = new Socket("127.0.0.1",8852);
    DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
    dataOutputStream.writeUTF("Hello socket");
    socket.close();
    }
}

注意別忘了拋出異常,這里只是個演示作用,直接throws Exception了。這里你直接運行肯定是不能建立連接的,因為服務器端還沒寫。

這里,假如你知道服務器監聽的是8852端口,你創建了一個socket來和它進行通信。socket.getOutputStream()得到這個socket的輸出流,當你調用writeUTF()方法時,便會向其中寫一個字符串。

典型三段式要牢記:打開、通信、關閉。

服務器端編程

注意了注意了,要開始造女票了。

初始版本代碼

import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(8852);
        System.out.println("Server 等待接收數據~");
        Socket socket = serverSocket.accept();
        DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
        String string = dataInputStream.readUTF();
        System.out.println(string);
        System.out.println("Server 接收數據完畢,拜拜了您~");
        socket.close();
        serverSocket.close();
    }
}    

這里服務器端用到了ServerSocket,負責接收客戶端的連接請求。你的暗戀對象可能有好多人要向她告白,一個Socket自然無法處理。通過ServerSocket的accept方法從連接請求隊列中取出一個進行連接。那這個ServerSocket就是你暗戀對象的室友,幫助她管理諸多“告白”。

這里只是把服務器端接收到的數據打印了一下便關閉了。至此,一個簡單的服務器-客戶端通信便建立了。但是這個服務器只能處理一個連接便關閉了,我們可以改進一下。

往下看之前請確保你大致理解了上述過程,最好自己敲一下代碼

到這里你可能會想,只處理一個就關閉了,那我加個while循環,讓它一直運行怎么樣?

聽着還可以,那我們來試驗一下(下面只是分析一下,不用跟着敲)。

將服務器端代碼更改為:

while(true)
{
  Socket socket = serverSocket.accept();
  DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
  String string = dataInputStream.readUTF();
  System.out.println(string);
  socket.close();
  serverSocket.close();
}     

這個會出現什么問題?客戶端正連着呢,啪,你服務器給人家斷開了,而且accept()接受的是socket請求,所以這種情況,除非客戶端再連一次,否則二者的通信就斷了。

你可能會說,那我把Socket移到外面呢?

其實吧,這個仔細理一下就會明白,如果放到外面的話,只要你想接收多個socket,就要把

Socket socket = serverSocket.accept();放到while循環中,但是你只要把它放到while循環中,它就只能和一個socket進行通信。這里有興趣可以再查閱一下資料,下面直接進入線程階段。

服務器端線程代碼

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {

    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(8852);
        System.out.println("Server 等待接收數據~");
        while(true) {
            Socket socket = serverSocket.accept();
       //這里來一個連接請求就讓deal去處理,自己在這里等下一個連接請求 deal(socket); } }
public static void deal(Socket client){
     //這里創建了一個新的線程
new Thread(new Runnable() { @Override public void run() { DataInputStream dataInputStream=null; DataOutputStream dataOutputStream = null; String receiveFromClient=""; try { dataInputStream = new DataInputStream(client.getInputStream()); dataOutputStream = new DataOutputStream(client.getOutputStream()); //只是這個線程中一直while循環,不影響其他的線程。 while(true) { receiveFromClient = dataInputStream.readUTF(); System.out.println("receive: "+receiveFromClient); if(receiveFromClient.equals("bye")) { dataOutputStream.writeUTF("終於厭倦我了嗎?客戶端都是大豬蹄子!!"); dataOutputStream.flush(); break; } else { dataOutputStream.writeUTF("你TM給我發 "+receiveFromClient+" 干什么?"); dataOutputStream.flush(); } } }catch (Exception e) { e.printStackTrace(); }finally { try { dataInputStream.close(); dataOutputStream.close(); client.close(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } }

客戶端代碼:

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class MyClient {
    public static void main(String[] args) throws Exception{
        Socket socket = new Socket("127.0.0.1",8852);
        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
        DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
        BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
        String string;
        while(true)
        {
            string=bReader.readLine();
            dataOutputStream.writeUTF(string);
            System.out.println(dataInputStream.readUTF());
            dataOutputStream.flush();
            if(string.equals("bye"))
                break;
        }
        socket.close();
    }
}

結果展示:

服務器端:

客戶端:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM