Java-socket編程(建立連接)


socket編程是以IO為理論基礎的,理論學得差不多也很難實現編程,畢竟里面的類和方法平時都不怎么用,難得嘗試編了個程,記錄一下。

1.幾個概念

Channel:管道,連通客戶端和服務端傳輸數據;

Buffer:緩沖區,通過管道傳輸數據必須經過的地方;

Selector:選擇器,單線程可以通過選擇器處理多個管道;本文沒有使用;

2.案例功能

啟動服務端,再啟動客戶端與服務端連接,在客戶端的控制台輸入命令獲取服務端的效果。本樣例只處理了“time”命令,獲取服務端的當前時間,其他命令都返回“非指定命令,無返回值”。詳看代碼注釋。

3.服務端代碼

 1 import java.net.InetSocketAddress;
 2 import java.nio.ByteBuffer;
 3 import java.nio.channels.ServerSocketChannel;
 4 import java.nio.channels.SocketChannel;
 5 import java.nio.charset.StandardCharsets;
 6 import java.util.Date;
 7 import java.util.LinkedList;
 8 
 9 public class NIOService {
10     static int PORT = 9011;
11     public static void main(String[] args) throws Exception{
12         //存儲客戶端連接
13         LinkedList<SocketChannel> clients = new LinkedList<>();
14         //1.服務端開啟監聽:接受客戶端
15         ServerSocketChannel ss = ServerSocketChannel.open();
16         ss.bind(new InetSocketAddress(PORT));
17         //2.只接受客戶端,不阻塞
18         ss.configureBlocking(false);
19 
20         while (true) {
21             // 接受客戶端的連接
22             // client在Java層面是一個對象,在內核層面是一個fd
23             SocketChannel client = ss.accept();
24             if (client == null) {
25                 //while循環進來沒有 連到客戶端就不管
26             } else {
27                 //和client傳輸數據使用的socket->fd
28                 client.configureBlocking(false);
29                 //獲取客戶端的端口號
30                 int port = client.socket().getPort();
31                 System.out.println("接收到客戶端的連接,client port: " + port);
32                 //將客戶端添加到列表里
33                 clients.add(client);
34             }
35             //可以在堆里,堆外,相關內容,可以看看JVM直接內存
36             ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
37 
38             //遍歷已經鏈接進來的客戶端 的管道channel里有沒有數據
39             for (SocketChannel c : clients) {
40                 //每循環一次都是一次系統調用,都是一次用戶內核態的切換
41                 int num = c.read(buffer);
42                 if (num > 0) {
43                     buffer.flip();
44                     byte[] bytes = new byte[buffer.limit()];
45                     buffer.get(bytes);
46                     String s = new String(bytes);
47                     System.out.println("端口為"+c.socket().getPort() + "的客戶端發來命令:" +s);
48                     String res = "";
49                     ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4096);
50                     if("time".equals(s)){
51                         //獲取時間
52                         long l = System.currentTimeMillis();
53                         res = "time: "+new Date(l).toString();
54                         System.out.println(res);
55                     }else{
56                         res = "非指定命令,無返回值";
57                     }
58                     byteBuffer.put(res.getBytes(StandardCharsets.UTF_8));
59                     byteBuffer.flip();
60                     c.write(byteBuffer);
61                 }
62                 buffer.clear();
63             }
64         }
65     }
66 }

 4.客戶端代碼

 1 import java.io.*;
 2 import java.net.Socket;
 3 import java.nio.channels.ServerSocketChannel;
 4 import java.nio.channels.SocketChannel;
 5 import java.util.Scanner;
 6 
 7 public class Client {
 8     public static void main(String[] args) {
 9         try {
10             //建立一個客戶端連到9010的服務端
11             Socket client = new Socket("127.0.0.1",9011);
12             //設置發送命令的長度
13             client.setSendBufferSize(20);
14             /**
15              * 關閉Nagle算法:該算法是將多個命令打包一起發送給服務端,避免網絡擁擠。
16              * 但是現在網絡寬松,隨便發也沒事。所以關閉。
17              */
18             client.setTcpNoDelay(false);
19 
20             OutputStream out = client.getOutputStream();
21             InputStream input = client.getInputStream();
22             InputStream in = System.in;
23             BufferedReader reader = new BufferedReader(new InputStreamReader(in));
24             Scanner scan = new Scanner(System.in);
25             while(true){
26                 String line = scan.nextLine();
27                 //String line = reader.readLine();
28                 if(line != null ){
29                     //將輸入的命令用字節數組存起來,通過客戶端client的輸出流發送給服務端
30                     byte[] bb = line.getBytes();
31                     out.write(bb);
32                 }
33                 byte b[] = new byte[1024];
34                 /**
35                  從輸入流里讀 東西 到 b數組,如果沒有東西,就會一直讀,阻塞。
36                  len獲取當前輸入流里的內容長度,英文占1個長度,中文占3個長度
37                  */
38                 int len = input.read(b);
39                 System.out.println(new String(b));
40             }
41         } catch (IOException e) {
42             e.printStackTrace();
43         }
44     }
45 
46 }

 


免責聲明!

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



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