Java客戶套接字類 Socket
服務(wù)器套接字類 ServerSocket
字符串讀/寫類 BuffferedReader/PrintWriter。
-
服務(wù)進(jìn)程首先被動打開一個監(jiān)聽端口,如8008,客戶進(jìn)程主動訪問這個端口,完成對話聊天前的TCP三次握手連接。TCP連接成功后,通信進(jìn)程的雙方具有兩個流(輸出流和輸入流)。邏輯上可將兩個流理解為兩個通信管道的全雙工通信模式,一個用于向?qū)Ψ桨l(fā)送數(shù)據(jù),另一個用于接收對方的數(shù)據(jù)。
image.png -
套接字類有兩個基本的方法可以獲得兩個通信管道的入口:
- Socket.getInputStream()方法可獲得輸入字節(jié)流的入口地址;
- Socket.getOutputStream()方法可獲得輸出字節(jié)流的出口地址;
-
socket.close() 實現(xiàn)四次握手?jǐn)嚅_
image.png
TCP客戶端
import java.net.*;
import java.io.*;
public class TCPClient {
//嵌套字程序設(shè)計
private Socket socket = null;
//用于字符和字節(jié)轉(zhuǎn)換的變量
private PrintWriter pw;
private BufferedReader br;
public TCPClient(String ip, String port) throws IOException{
//主動向服務(wù)器發(fā)起連接,實現(xiàn)TCP中三次握手的過程
socket = new Socket(ip, Integer.parseInt(port));
//若不成功(網(wǎng)絡(luò)問題,地址錯誤,服務(wù)器資源緊張等),拋出錯誤,其錯誤信息交由調(diào)用者處理
//若成功,做下面兩件事
//得到網(wǎng)絡(luò)輸出字節(jié)流地址,并裝飾成網(wǎng)絡(luò)輸出字符流
OutputStream socketOut = socket.getOutputStream();
pw = new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
// pw.flush();
//得到網(wǎng)絡(luò)輸入流地址,并裝飾成網(wǎng)絡(luò)輸入字符流
InputStream socketIn = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(socketIn,"GB2312"));
}
public void send(String msg){
pw.println(msg+"\n");
pw.flush();
//輸出字符流,由Socket調(diào)用系統(tǒng)底層函數(shù),經(jīng)網(wǎng)卡發(fā)送字節(jié)流
}
public String receive(){
String msg;
try{
//從網(wǎng)絡(luò)輸入字符流中讀信息,每次只能接收一行信息
//若不夠一行(無行結(jié)束符),該語句阻塞,直到條件滿足,程序才往下運行
msg = br.readLine();
}catch(IOException ex){
msg = null;
}
return msg;
}
public void close(){
try{
if(socket != null){
//實現(xiàn)三次握手
socket.close();
}
}catch(IOException ex){}
}
//模塊內(nèi)測試與運行,需要先運行TCPServer
//
// public static void main(String args[])throws IOException{
// TCPClient tc = new TCPClient("127.0.0.1","8008");
// ec.send("123456789"); //發(fā)送一行字符
// System.out.println(ec.receive());//接受一行字符串并在屏幕上顯示
// tc.close();
//
// }
}
TCP服務(wù)器
import java.io.*;
import java.net.*;
public class TCPServer {
private int port = 8008;
//服務(wù)器嵌套字
private ServerSocket serverSocket;
public TCPServer()throws IOException{
//開啟8008監(jiān)聽端口
serverSocket = new ServerSocket(8008);
System.out.println("服務(wù)器啟動");
}
private PrintWriter putWriter(Socket socket)throws IOException{
OutputStream socketOut = socket.getOutputStream();//獲得輸出流緩沖區(qū)的地址
return new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
}
private BufferedReader getReader(Socket socket)throws IOException{
InputStream socketIn = socket.getInputStream();//獲得輸入流緩沖區(qū)的地址
return new BufferedReader(new InputStreamReader(socketIn,"GB2312"));
}
public void service(){
//單客戶版本,每次只能同時和一個客戶建立通信連接
while(true){
Socket socket = null;
try{
//阻塞語句,監(jiān)聽并等待客戶發(fā)起連接,有連接請求就生成一個嵌套字
socket = serverSocket.accept();
//本地服務(wù)器觀測臺顯示請求的用戶信息
System.out.println("新用戶:" + socket.getInetAddress());
BufferedReader br = getReader(socket);//定義字符串輸入流
PrintWriter pw = putWriter(socket); //定義字符串輸出流
String msg;
//阻塞語句,從輸入流讀入一行字符串
while((msg = br.readLine())!=null){
pw.println("來自服務(wù)器:" + msg); //先輸出流輸出一行字符串
// pw.flush();
if(msg.equals("bye")) //如果客戶發(fā)送的消息為"bye",就結(jié)束通信
break;
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(socket!=null)
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
public static void main(String args[])throws IOException{
new TCPServer().service();
}
}

