基於Socket的客戶端服務端通信--Java GUI界面小程序
Socket概念及其通信過程:
Socket是TCP/IP中的基本概念,它負責將TCP/IP包發送到指定的IP地址。也可以看成是在兩個程序進行通信連接中的一個端點,一個程序將 信息寫入Socket中(類似於插座),該Socket將這段信息發送到另一個Socket中(類似於插頭),使這段信息能夠傳送到其他程序。這兩端的程序可以是在一臺計算機 上,也可以在因特網的遠程計算機上。
當兩個程序需要通信時,可以使用Socket類建立套接字連接。呼叫的一方稱爲客戶機,負責監聽的一方稱爲服務器。 由於TCP/IP協議是基於連接的、可靠的協議,所以客戶機服務器可以在這條連接上可靠地傳輸數據。服務器所用的套接字是ServerSocket, 客戶機所用的套接字是Socket。一個Socket由一個IP地址和一 個端口號唯一確定 。
在傳統的UNIX環境下可以操作TCP/IP協議的接口不止Socket一個,Socket 所支持的協議種類也不光TCP/IP -種,因此兩者之間是沒有必然聯繫的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網絡編程。
使用Socket 進行Client/Server程序設計的一般連接過程 是這樣的: Server 端Listen (監聽)某個端口是否有連接請求,Client 端向Server端發出Connect (連接)請求,Server 端向Client端發回Accept (接收)消息。-個連接就建 立起來了。Server 端和Client端都可以通過Send和Write等方法與對方通信。
對於一個功能齊全的Socket,其工作過程包含以下4個基本的步驟。
- 創建Socket
- 打開連接到Socket的輸入/輸出流。
- 按照一定的協議對Socket進行讀寫操作。
- 關閉Socket。
當用戶輸入一行文字時,程序將接受數據部分放在線程中,它始終在後臺運行,一旦對方發來數據,就立即顯示在界面上。而主界面負責輸入文字和發送數據,這樣發送和接受數據互不影響。
服務端代碼:
import java.io.*;
import java.net. *;
import java. awt.event. *;
import java.awt.*;
import javax. swing.*;
public class ChatServer implements ActionListener, Runnable {
JTextArea showArea;
JTextField msgText;
JFrame mainJframe;
JButton sentBtn;
JScrollPane JSPane;
JPanel pane;
Container con;
Thread thread = null;
ServerSocket serverSocket;
Socket connectToClient;
DataInputStream inFromClient;
DataOutputStream outToClient;
public ChatServer() {
//設置界面
mainJframe = new JFrame("聊天——服務端");
con = mainJframe.getContentPane();
showArea = new JTextArea();
showArea.setEditable(false);
showArea.setLineWrap(true);
JSPane = new JScrollPane(showArea);
msgText = new JTextField();
msgText.setColumns(30);
msgText.addActionListener(this);
sentBtn = new JButton("發送");
sentBtn.addActionListener(this);
pane = new JPanel();
pane.setLayout(new FlowLayout());
pane.add(msgText);
pane.add(sentBtn);
con.add(JSPane, BorderLayout.CENTER);
con.add(pane, BorderLayout.SOUTH);
mainJframe.setSize(500, 400);
mainJframe.setVisible(true);
mainJframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
;
try {
//創建服務套接字
serverSocket = new ServerSocket(5500);
showArea.append("正在等待對話請求...\n");//偵聽客戶端的連接
connectToClient = serverSocket.accept();
inFromClient = new DataInputStream(connectToClient.getInputStream());
outToClient = new DataOutputStream(connectToClient.getOutputStream());
//啓動線程在後臺來接收對方的消息
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
} catch (IOException e) {
showArea.append("對不起,不能創建服務器\n");
msgText.setEditable(false);
sentBtn.setEnabled(false);
}
}
public static void main(String[] args){
new ChatServer();
}
@Override
//響應按鈕事件,發送消息給對方
public void actionPerformed(ActionEvent e) {
String s = msgText.getText();
if (s.length() > 0) {
try {
outToClient.writeUTF(s);
outToClient.flush();
showArea.append("我(服務端)說:" + msgText.getText() + "\n");
msgText.setText(null);
} catch (IOException el) {
showArea.append("你的消息:“" + msgText.getText() + "”未能發出去!\n");
}
}
}
@Override
//本線程負責將客戶機傳來的信息顯示在對話區域
public void run() {
try{
while (true){
showArea.append("客戶端說:"+inFromClient.readUTF()+"\n");
Thread.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
客戶端代碼:
import java.io.*;
import java .net.*;
import java. awt.event.*;
import java.awt.*;
import javax. swing.*;
public class ChatClient implements ActionListener,Runnable{
JTextArea showArea;
JTextField msgText;
JFrame mainJframe;
JButton sentBtn;
JScrollPane JSPane;
JPanel pane;
Container con;
Thread thread=null;
Socket connectToServer;
DataInputStream inFromServer;
DataOutputStream outToServer;
public ChatClient(){
mainJframe=new JFrame("聊天——客戶端");
con=mainJframe.getContentPane();
showArea=new JTextArea();
showArea.setEditable(false);
showArea.setLineWrap(true);
JSPane=new JScrollPane(showArea);
msgText=new JTextField();
msgText.setColumns(30);
msgText.addActionListener(this);
sentBtn=new JButton("發送");
sentBtn.addActionListener(this);
pane=new JPanel();
pane.setLayout(new FlowLayout());
pane.add(msgText);
pane.add(sentBtn);
con.add(JSPane, BorderLayout.CENTER);
con.add(pane, BorderLayout.SOUTH);
mainJframe.setSize (500 ,400);
mainJframe.setVisible (true);
mainJframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//創建套接字連接到服務器
try{
connectToServer=new Socket("localhost",5500);
inFromServer=new DataInputStream(connectToServer.getInputStream());
outToServer=new DataOutputStream(connectToServer .getOutputStream());
showArea.append("連接成功,請說話...\n");
//創建線程在後臺處理對方的消息
thread=new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
} catch (UnknownHostException e1){
e1.printStackTrace();
} catch (IOException e1){
showArea.append("抱歉,未能連接到服務器!\n");
msgText.setEditable(false);
sentBtn.setEnabled(false);
}
}
public static void main(String[] args){
new ChatClient();
}
@Override
//
public void actionPerformed(ActionEvent e){
String s=msgText.getText();
if (s.length()>0){
try{
outToServer.writeUTF(s);
outToServer.flush();
showArea.append("我(客戶端)說: "+msgText. getText()+"\n");
} catch (IOException e1){
showArea.append("你的消息:“"+msgText.getText()+"”未能發送出去!\n");
}
}
}
//本線程負責將服務器傳來的消息顯示在對話區域
public void run(){
try{
while (true){
showArea.append("服務端說:"+inFromServer.readUTF()+"\n");
Thread.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
編譯後首先運行服務端,在運行客戶端。截圖如下: