欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Socket編程簡單示例(聊天服務(wù)器)

 更新時間:2023年02月18日 14:15:14   作者:念念清晰  
socket編程是在不同的進(jìn)程間進(jìn)行網(wǎng)絡(luò)通訊的一種協(xié)議,下面這篇文章主要給大家介紹了關(guān)于Socket編程簡單示例的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下

傳統(tǒng)Socket基于BIO實現(xiàn)一個簡單的聊天服務(wù)器

服務(wù)端代碼如下

public class MyServerSocket {
  public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket();
    // 綁定5000端口
    serverSocket.bind(new InetSocketAddress("127.0.0.1", 5000));
    System.out.println("服務(wù)端啟動成功...");
    while (true) {
      // 如果獲取不到socket就會一致阻塞在此
      Socket socket = serverSocket.accept();
      InputStream is = socket.getInputStream();
      byte[] buf = new byte[1024];
      int len = is.read(buf);
      System.out.println("客戶端說:" + new String(buf, 0, len, StandardCharsets.UTF_8));
      OutputStream os = socket.getOutputStream();
      os.write("你好客戶端,我收到你的消息了".getBytes(StandardCharsets.UTF_8));
    }
  }
}

客戶端代碼如下

public class ClientSocket {
  public static void main(String[] args) throws IOException {
    Socket socket = new Socket();
    socket.connect(new InetSocketAddress("127.0.0.1",5000));
    OutputStream os = socket.getOutputStream();
    os.write("hello服務(wù)端~".getBytes(StandardCharsets.UTF_8));
    InputStream is = socket.getInputStream();
    byte[] buf = new byte[1024];
    int len = is.read(buf);
    System.out.println("服務(wù)器說:" + new String(buf, 0, len, StandardCharsets.UTF_8));
  }
}

先啟動服務(wù)器端,再啟動客戶端。即可

傳統(tǒng)BIO是阻塞的,舉個燒水的例子來理解

Socket編寫一個簡單的Http服務(wù)器

http服務(wù)器的代碼

public class HttpServer {
  private static String response = """
      HTTP/1.1 200 OK
      content-type: text/html
            
      <h1>hello,client</h1>
      """;

  public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket();
    serverSocket.bind(new InetSocketAddress("127.0.0.1", 5001));
    System.out.println("HTTP服務(wù)器啟動成功");
    while (true) {
      Socket client = serverSocket.accept();
      // 獲取客戶端發(fā)送過來的數(shù)據(jù)
      InputStream is = client.getInputStream();
      byte[] buf = new byte[1024];
      int len = is.read(buf);
      System.out.println("客戶端發(fā)送過來的數(shù)據(jù):" + new String(buf, 0, len, StandardCharsets.UTF_8));
      // 給客戶端響應(yīng)HTTP協(xié)議的數(shù)據(jù)
      OutputStream os = client.getOutputStream();
      os.write(response.getBytes(StandardCharsets.UTF_8));
      // 注意:要關(guān)閉客戶端資源
      client.close();
    }
  }
}

只要響應(yīng)數(shù)據(jù)滿足HTTP協(xié)議,就可以通過瀏覽器訪問到頁面,下面我們使用瀏覽器訪問下

基于NIO的非阻塞簡單服務(wù)器實現(xiàn)

傳統(tǒng)BIO會阻塞,使用NIO通道編程可以設(shè)置服務(wù)器為非阻塞,當(dāng)未獲取到連接時,可以處理其他的邏輯。相當(dāng)于線程模型換了。下面是服務(wù)端代碼,客戶端代碼不變,采用BIO的即可

public class NioServerSocket {
  public static void main(String[] args) throws IOException, InterruptedException {
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 5002));
    serverSocketChannel.configureBlocking(false); // 設(shè)置非阻塞
    while (true) {
      SocketChannel clientChannel = serverSocketChannel.accept();
      if (clientChannel == null) {
        System.out.println("客戶端無連接,休息一下");
        Thread.sleep(1000);
        continue;
      }
      Socket socket = clientChannel.socket();
      InputStream is = socket.getInputStream();
      byte[] buf = new byte[1024];
      int len = is.read(buf);
      System.out.println("客戶端發(fā)送過來的數(shù)據(jù):" + new String(buf, 0, len, StandardCharsets.UTF_8));
      socket.close();
      clientChannel.close();
    }
  }
}

第二種實現(xiàn)方式如下

public class NioServerSocket2 {
  public static void main(String[] args) throws IOException, InterruptedException {
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 5002));
    serverSocketChannel.configureBlocking(false); // 設(shè)置非阻塞
    while (true) {
      SocketChannel clientChannel = serverSocketChannel.accept();
      if (clientChannel == null) {
        System.out.println("客戶端無連接,休息一下");
        Thread.sleep(1000);
        continue;
      }
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      int len = clientChannel.read(buffer);
      System.out.println("客戶端說" + new String(buffer.array(), 0, len));
      clientChannel.close();
    }
  }
}

但是該實現(xiàn)也有一個問題:雖然客戶端的連接過程不會阻塞了,但是客戶端發(fā)送數(shù)據(jù)會阻塞服務(wù)端。如果客戶端發(fā)送數(shù)據(jù)過大,假設(shè)要10秒,那服務(wù)端調(diào)用read方法讀取數(shù)據(jù)就要等待客戶端至少10秒。

基于NIO的Selector的簡單服務(wù)器實現(xiàn)

selector的服務(wù)端如下,這是要給單線程的服務(wù)端。相比上一小節(jié)沒有使用selector,它的優(yōu)點就是連接事件和讀事件都不會阻塞了。即使客戶端發(fā)送數(shù)據(jù)很慢,服務(wù)端也不會阻塞。

缺點是單線程執(zhí)行,如果一個線程搶到讀就緒事件并且處理的很慢,就會影響整體性能。

public class NioSelectorServerSocket {
  public static void main(String[] args) throws Exception {
    // 1. 獲取通道
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 5003));
    serverSocketChannel.configureBlocking(false);
    // 2. 獲取選擇器
    Selector selector = Selector.open();
    // 3. 把通道注冊到選擇器上,只注冊連接繼續(xù)事件
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    System.out.println("服務(wù)器啟動成功...");
    while (true) {
      // 4. 不斷輪詢選擇器中是否由連接事件
      int select = selector.select(2000);
      if (select == 0) {
        System.out.println("暫時沒有客戶端連接哦");
        continue;
      }
      // 5. 如果有連接繼續(xù)事件,獲取客戶端通道
      Set<SelectionKey> selectionKeys = selector.selectedKeys();
      Iterator<SelectionKey> iterator = selectionKeys.iterator();
      while (iterator.hasNext()) {
        SelectionKey key = iterator.next();
        if (key.isAcceptable()) {
          SocketChannel client = serverSocketChannel.accept();
          //SocketChannel client = ((ServerSocketChannel) key.channel()).accept(); // 兩種寫法都一樣
          client.configureBlocking(false);
          // 6. 為每個連接都注冊寫事件監(jiān)聽
          client.register(selector, SelectionKey.OP_READ);
          System.out.println("已注冊可讀事件");
        }
        if (key.isReadable()) {
          SocketChannel client = (SocketChannel) key.channel();
          // 7. 監(jiān)聽到可讀事件,處理可讀事件
          ByteBuffer buffer = ByteBuffer.allocate(1024);
          int len = client.read(buffer);
          System.out.println("客戶端說:" + (len > 0 ? new String(buffer.array(), 0, len, StandardCharsets.UTF_8) : ""));
          // 8. 關(guān)閉資源
          client.close();
        }
        iterator.remove();
      }
    }
  }
}

它的線程模型還是用燒水的例子來舉例

總結(jié)

到此這篇關(guān)于Socket編程簡單示例的文章就介紹到這了,更多相關(guān)Socket編程示例內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java線程池的拒絕策略實現(xiàn)詳解

    Java線程池的拒絕策略實現(xiàn)詳解

    這篇文章主要介紹了Java線程池的拒絕策略實現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Druid核心源碼解析DruidDataSource

    Druid核心源碼解析DruidDataSource

    這篇文章主要為大家介紹了Druid核心源碼解析DruidDataSource,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Java線程中的ThreadLocal類解讀

    Java線程中的ThreadLocal類解讀

    這篇文章主要介紹了Java線程中的ThreadLocal類解讀,ThreadLocal是一個泛型類,作用是實現(xiàn)線程隔離,ThreadLocal類型的變量,在每個線程中都會對應(yīng)一個具體對象,對象類型需要在聲明ThreadLocal變量時指定,需要的朋友可以參考下
    2023-11-11
  • JDK生成WebService客戶端代碼以及調(diào)用方式

    JDK生成WebService客戶端代碼以及調(diào)用方式

    WebService 是一種跨編程語言和跨操作系統(tǒng)平臺的遠(yuǎn)程調(diào)用技術(shù),下面這篇文章主要給大家介紹了關(guān)于JDK生成WebService客戶端代碼以及調(diào)用方式的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08
  • java創(chuàng)建線程的兩種方法區(qū)別

    java創(chuàng)建線程的兩種方法區(qū)別

    這篇文章主要為大家區(qū)分了java創(chuàng)建線程的兩種方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • IDEA中Java出現(xiàn)無效的源發(fā)行版錯誤的解決辦法

    IDEA中Java出現(xiàn)無效的源發(fā)行版錯誤的解決辦法

    這篇文章主要給大家介紹了關(guān)于IDEA中Java出現(xiàn)無效的源發(fā)行版錯誤的解決辦法,IDEA中Java出現(xiàn)?效的源發(fā)?版解決辦法出現(xiàn)該問題的原因是項?Project當(dāng)中的jdk與電腦當(dāng)中的jdk版本不?致造成的,需要的朋友可以參考下
    2023-10-10
  • Java使用junit框架進(jìn)行代碼測試過程詳解

    Java使用junit框架進(jìn)行代碼測試過程詳解

    單元測試就是針對最小的功能單元編寫測試代碼,Junit是使用Java語言實現(xiàn)的單元測試框架,它是開源的,Java開發(fā)者都應(yīng)當(dāng)學(xué)習(xí)并使用Junit編寫單元測試。本文就來講講Junit框架的使用教程,需要的可以參考一下
    2023-02-02
  • 解決springboot的JPA在Mysql8新增記錄失敗的問題

    解決springboot的JPA在Mysql8新增記錄失敗的問題

    這篇文章主要介紹了解決springboot的JPA在Mysql8新增記錄失敗的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • SpringBoot無法訪問webapp目錄下的文件問題

    SpringBoot無法訪問webapp目錄下的文件問題

    這篇文章主要介紹了SpringBoot無法訪問webapp目錄下的文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 超詳細(xì)講解Java異常

    超詳細(xì)講解Java異常

    Java 異常機(jī)制可以使程序中異常處理代碼和正常業(yè)務(wù)代碼分離,保證程序代碼更加優(yōu)雅,并提高程序健壯性。本文超詳細(xì)講解了Java異常,感興趣的小伙伴可以參考一下這篇文章
    2021-09-09

最新評論