《Java開發實戰1200例》(第2卷)學習筆記—TCP套接字
Socket基礎
例項307:建立伺服器套接字
-通過ServerSocket類建立繫結到指定埠的伺服器套接字物件,然後呼叫ServerSocket類的accept()方法監聽客戶端的連線。
全部程式碼如下:
import java.awt.BorderLayout;
import java.net.*;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ServerSocketFrame extends JFrame {
private JTextArea ta_info;
private ServerSocket server; // 宣告ServerSocket物件
private Socket socket; // 宣告Socket物件socket
public void getServer() {
try {
server = new ServerSocket(1978); // 例項化Socket物件
ta_info.append("伺服器套接字已經建立成功\n"); // 輸出資訊
while (true) { // 如果套接字是連線狀態
ta_info.append("等待客戶機的連線......\n"); // 輸出資訊
socket = server.accept(); // 例項化Socket物件
ta_info.append("連線成功......\n");
}
} catch (Exception e) {
e.printStackTrace(); // 輸出異常資訊
}
}
public static void main(String[] args) { // 主方法
ServerSocketFrame frame = new ServerSocketFrame(); // 建立本類物件
frame.setVisible(true);
frame.getServer(); // 呼叫方法
}
public ServerSocketFrame() {
super();
setTitle("建立伺服器套接字");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 260, 167);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
}
}
注意:在進行套接字程式設計時,應該使用大於1024的埠號,這樣可以避免埠衝突,因為0~1024之間的埠已經被一些特殊的協議和服務所佔用,如80埠被HTTP協議所佔用、21埠被FTP服務所佔用等。
例項308:建立客戶端套接字
通過Socket類建立到指定伺服器和埠的套接字物件,從而實現與伺服器的連線。
全部程式碼如下:
import java.awt.BorderLayout;
import java.net.*;
import javax.swing.*;
import javax.swing.JScrollPane;
public class ClientSocketFrame extends JFrame { // 建立類繼承JFrame類
private Socket socket; // 宣告Socket物件
private JTextArea ta_info = new JTextArea(); // 建立JtextArea物件
public ClientSocketFrame() { // 構造方法
super(); // 呼叫父類的構造方法
setTitle("建立客戶端套接字");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 254, 166);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(ta_info);
}
private void connect() { // 連線套接字方法
ta_info.append("嘗試連線......\n"); // 文字域中資訊資訊
try { // 捕捉異常
socket = new Socket("127.0.0.1", 1978); // 例項化Socket物件
ta_info.append("完成連線。\n"); // 文字域中提示資訊
} catch (Exception e) {
e.printStackTrace(); // 輸出異常資訊
}
}
public static void main(String[] args) { // 主方法
ClientSocketFrame clien = new ClientSocketFrame(); // 建立本例物件
clien.setVisible(true); // 將窗體顯示
clien.connect(); // 呼叫連線方法
}
}
注意:本例單獨執行時會發生異常,因此需要先執行例項307.
在使用Socket類建立客戶端套接字時,所指定的IP地址和埠號一定要與伺服器相同,否則將無法連線到伺服器。
例項309:設定等待連線的超時時間
通過ServerSocket類的例項呼叫setSoTimeout()方法,設定連線的等待超時時間,從而實現設定等待連線的超時時間。
主要程式碼如下:
server=new ServerSocket(1978);
server.setSoTimeout(10000);//設定連線超時時間為10秒
注意:可以使用Socket類的setTcpNoDelay()方法,將引數設定為true,禁用網路傳輸中的資料延遲;設定為false,啟用資料延遲。對於一般的網路通訊,是允許資料延遲的,而對於一些特殊的網路應用,如果允許資料延遲,將會極大地影響資料傳輸的速度,例如需要實時監控的網路程式以及遊戲,就必須禁用資料延遲。
例項310:獲取Socket資訊
通過Socket類的getInetAddress()方法獲得遠端伺服器的地址,使用getLocalAddress()方法獲得客戶端的地址實現的。
主要程式碼如下:
socket=new Socket("伺服器IP地址",埠號);//例項化Socket物件
InetAddress netAddress=socket.getInetAddress();//獲得遠端伺服器的地址
String netIp=netAddress.getHostAddress();//獲得遠端伺服器的地址
int netPort=socket.getPort();//獲得遠端伺服器的埠號
InetAddress localAddress=socket.getLocalAddress();//獲得客戶端的地址
String localIp=localAddress.getHostAddress();//獲得客戶端的IP地址
int localPort=socket.getLocalPort();//獲得客戶端的埠號
接收和傳送Socket資訊
本例項主要是通過Socket類的getInputStream()方法獲得輸入流物件,使用getOutputStream()方法獲得輸出流物件實現的。
全部程式碼如下:
//客戶端程式
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import javax.swing.JScrollPane;
public class ClientSocketFrame extends JFrame { // 建立類繼承JFrame類
private PrintWriter writer; // 宣告PrintWriter類物件
private Socket socket; // 宣告Socket物件
private JTextArea ta_info = new JTextArea(); // 建立JtextArea物件
private JTextField tf_send = new JTextField(); // 建立JtextField物件
private Container cc; // 宣告Container物件
public ClientSocketFrame() { // 構造方法
super(); // 呼叫父類的構造方法
setTitle("客戶端程式");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 351, 257);
cc = this.getContentPane(); // 例項化物件
cc.add(tf_send, "South"); // 將文字框放在窗體的下部
tf_send.addActionListener(new ActionListener() { // 繫結事件
public void actionPerformed(ActionEvent e) {
writer.println(tf_send.getText()); // 將文字框中資訊寫入流
ta_info.append("客戶端傳送的資訊是:" + tf_send.getText() + "\n"); // 將文字框中資訊顯示在文字域中
tf_send.setText(""); // 將文字框清空
}
});
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(ta_info);
}
private void connect() { // 連線套接字方法
ta_info.append("嘗試連線......\n"); // 文字域中資訊資訊
try { // 捕捉異常
socket = new Socket("192.168.1.193", 1978); // 例項化Socket物件
writer = new PrintWriter(socket.getOutputStream(), true);// 建立輸出流物件
ta_info.append("完成連線。\n"); // 文字域中提示資訊
} catch (Exception e) {
e.printStackTrace(); // 輸出異常資訊
}
}
public static void main(String[] args) { // 主方法
ClientSocketFrame clien = new ClientSocketFrame(); // 建立本例物件
clien.setVisible(true); // 將窗體顯示
clien.connect(); // 呼叫連線方法
}
}
//伺服器端程式
import java.awt.BorderLayout;
import java.io.*;
import java.net.*;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ServerSocketFrame extends JFrame {
private JTextArea ta_info;// 宣告文字域,用於顯示連線資訊和接收到的資訊
private BufferedReader reader; // 宣告BufferedReader物件
private ServerSocket server; // 宣告ServerSocket物件
private Socket socket; // 宣告Socket物件socket
public void getServer() {
try {
server = new ServerSocket(1978); // 例項化Socket物件
ta_info.append("伺服器套接字已經建立成功\n"); // 輸出資訊
while (true) { // 如果套接字是連線狀態
ta_info.append("等待客戶機的連線......\n"); // 輸出資訊
socket = server.accept(); // 例項化Socket物件
ta_info.append("連線成功。\n"); // 輸出資訊
reader = new BufferedReader(new InputStreamReader(socket
.getInputStream())); // 例項化BufferedReader物件
getClientInfo(); // 呼叫getClientInfo()方法
}
} catch (Exception e) {
e.printStackTrace(); // 輸出異常資訊
}
}
private void getClientInfo() {
try {
while (true) { // 如果套接字是連線狀態
ta_info.append("接收到客戶機發送的資訊:" + reader.readLine() + "\n"); // 獲得客戶端資訊
}
} catch (Exception e) {
ta_info.append("客戶端已退出。\n"); // 輸出異常資訊
} finally {
try {
if (reader != null) {
reader.close();// 關閉流
}
if (socket != null) {
socket.close(); // 關閉套接字
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) { // 主方法
ServerSocketFrame frame = new ServerSocketFrame(); // 建立本類物件
frame.setVisible(true);
frame.getServer(); // 呼叫方法
}
public ServerSocketFrame() {
super();
setTitle("伺服器端程式");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 336, 257);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
}
}
例項312:關閉Socket緩衝
通過Socket類的例項,呼叫setTcpNoDelay()方法,將引數設定為true來關閉Socket緩衝的。
主要程式碼如下:
socket=server.accept();//例項化Socket物件
socket.setTcpNoDelay(true);//關閉Socket緩衝,提高資料傳輸速度