代碼
服務器端
package socket_demo;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class server {
public static void main(String[] args) throws Exception {
// 監聽指定的端口,阻塞直至客戶端連接此端口
int port = 23333;
ServerSocket server = new ServerSocket(port);
System.out.println("server is waiting...");
Socket socket = server.accept();
System.out.println("Connected!");
// 讀取從客戶端返回的輸入流,至尾端時返回-1
InputStream input = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder get = new StringBuilder();
while ((len = input.read(bytes)) != -1) {
get.append(new String(bytes, 0, len, "UTF-8"));
}
System.out.println("get message from client: " + get);
OutputStream output = socket.getOutputStream();
String sent = "Hi there";
output.write(sent.getBytes("UTF-8"));
System.out.println("sent message to client: " + sent);
// 關閉socket與服務器端
input.close();
output.close();
socket.close();
server.close();
}
}
客戶端
package socket_demo;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class client {
public static void main(String args[]) throws Exception {
// 連接本地主機,端口自設,與服務端一致即可
String host = "127.0.0.1";
int port = 23333;
// 通過socket與服務端建立連接
Socket socket = new Socket(host, port);
if(socket.isConnected()){
System.out.println("Connected!");
}
// 將要發送的信息寫入輸出流
OutputStream output = socket.getOutputStream();
String sent = "hello";
socket.getOutputStream().write(sent.getBytes("UTF-8"));
// 關閉客戶端的輸出流(單向,並未關閉socket)
socket.shutdownOutput();
System.out.println("sent message to server: " + sent);
// 讀取從server返回的輸入流
InputStream input = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder get = new StringBuilder();
while ((len = input.read(bytes)) != -1) {
get.append(new String(bytes, 0, len,"UTF-8"));
}
System.out.println("get message from server: " + get);
// 關閉socket
input.close();
output.close();
socket.close();
}
}
測試結果
服務器端
客戶端
JAVA Socket API分析
以上代碼用到的JAVA SOCKET API主要有:
Socket(InetAddress address, int port)
--創建一個流套接字並將其連接到指定的IP地址與指定端口
ServerSocket(int port)
--服務器端綁定一個窗口
server.accept()
--服務器端等待連接(持續阻塞)
socket.getInputStream()
--返回此套接字的輸入流
socket.getOutputStream()
--返回此套接字的輸出流
socket.close()
--關閉此套接字
JAVA中方法的實現都要通過JVM翻譯給系統執行,所以JAVA SOCKET API與系統(本例為windows)SOCKET API有着對應關系。
我們通過在IDEA中使用Ctrl+Alt+H
與Ctrl+Alt+B
跟蹤查看api的調用棧,以server.accept()
為例
雙擊右邊函數名,查看其調用,進一步查看ServerSocket.implAccept(Socket)
這里accept0()
是一個native api,無法再繼續上溯
完整的調用棧為server.accept()
->ServerSocket.implAccept(Socket) (java.net)
->SocketImpl.accept(SocketImpl)
->AbstractPlainSocketImpl.socketAccept(SocketImpl)
->PlainSocketImpl.accept0(int, InetSocketAddress[])
綜上,java socket中的server.accept()
對應windows socket中的accept0(int var0, InetSocketAddress[] var1)
其它socket api也都有着類似的對應關系,通過查看調用棧可以一一查找,這里不再贅述