這次在java實驗的時候,要求使用server socket
編寫服務器和客戶端的網絡通信。最開始認爲應該是挺簡單的,但是後來發現低估了它。出現了不少的問題,所以也在這裏與大家分享。
問題描述
服務器程序的處理規則如下:
1) 向客戶端程序發送Verifying Server!。
2) 若讀口令次數超過3次,則發送Illegal User!給客戶端,程序退出。否則向下執行步驟3)。
3) 讀取客戶端程序提供的口令。
4) 若口令不正確,則發送PassWord Wrong!給客戶端,並轉步驟2),否則向下執行步驟5)。
5) 發送Registration Successful!給客戶端程序。客戶端程序的處理規則如下:
1) 讀取服務器反饋信息。
2) 若反饋信息不是Verifying Server!,則提示Server Wrong!,程序退出。否則向下執行步驟3)
3) 提示輸入PassWord並將輸入的口令發送給服務器。
4) 讀取服務器反饋信息。
5) 若反饋信息是Illegal User!,則提示Illegal User!,程序退出。否則向下執行步驟6)
6) 若反饋信息是PassWord Wrong!,則提示PassWord Wrong!,並轉步驟3),否則向下執行步驟。
7) 輸出Registration Successful!。
初步實現
首先,我們一定要清楚,這次和之前的程序不同,雖然都是在本地上,但是服務器
和客戶端
需要兩個啓動程序來實現,以達到我們模擬遠程連接的效果。
然後就是如何利用socket
實現我們的功能了。
通過上面的圖示,我們可以知道,首先需要先開啓服務器
,然後等待客戶端的連接。
當客戶端通過socket
進行連接後,服務器端也會建立一個socket
對象來幫助實現服務器和客戶端的通信。
這時候就建立了一個TCP連接
,我們就可以在服務器寫數據,然後在客戶端讀取了,實現雙方通信。
最後,當有一方決定通信結束,就會關閉連接。通信結束。
下面是初步實現的代碼:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服務器
*/
public class ServerTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8080);
Socket clientSocket = serverSocket.accept();
String welcome = "verifying server!";
OutputStream outputStream = clientSocket.getOutputStream();
outputStream.write(welcome.getBytes());
InputStream inputStream = clientSocket.getInputStream();
int time = 0;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String password = bufferedReader.readLine();
// 獲取登錄信息,允許3次登錄
while (time < 3) {
if (password.equals("123")) {
outputStream.flush();
outputStream.write("Registration Successful!".getBytes());
break;
} else {
outputStream.write("PassWord Wrong!".getBytes());
outputStream.flush();
password = bufferedReader.readLine();
time++;
}
}
if (time >= 3) {
outputStream.flush();
outputStream.write("Illegal User!".getBytes());
}
outputStream.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.Socket;
/**
* 客戶端
*/
public class ClientTest {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8080);
String aline = new String();
// 獲取輸入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
aline = bufferedReader.readLine();
// 訪問失敗
if (!aline.equals("verifying server!")) {
System.out.println("Server Wrong!");
return;
}
// 獲取響應結果
String feedback = bufferedReader.readLine();
while (feedback == null || feedback.equals("PassWord Wrong!")) {
if (feedback != null) {
if (feedback.equals("PassWord Wrong!")) {
System.out.println("PassWord Wrong!");
} else if (feedback.equals("Registration Successful!")) {
System.out.println("Registration Successful!");
break;
}
}
System.out.println("輸入密碼:");
// 輸入密碼
Scanner scanner = new Scanner(System.in);
OutputStream outputStream = socket.getOutputStream();
String password = scanner.nextLine();
outputStream.write(password.getBytes());
feedback = bufferedReader.readLine();
}
// 關閉連接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
初步實現後,運行:一片空白
。什麼都沒有發生。
出問題了很正常,斷點調試一下吧。發現問題所在:
客戶端執行到這一行時,停止,然後服務器端接着執行;
同樣的服務器端也到這行就停止了。
原因是服務器一方等着輸入密碼,而客戶端一方等着響應結果,然後又沒有開始輸入密碼。所以雙方就這麼一直等着,誰都不動了。
解決
通過上面的分析,我們只要將僵局打破就能夠解決問題。所以就先輸入密碼
,然後再獲取響應結果
。這樣就不會出問題了。
所以服務器端的代碼並不需要做什麼改動,只用修改客戶端程序就行了。
import java.io.*;
import java.net.Socket;
/**
* 客戶端
*/
public class ClientTest {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8080);
String aline = new String();
// 獲取輸入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
aline = bufferedReader.readLine();
// 訪問失敗
if (!aline.equals("verifying server!")) {
System.out.println("Server Wrong!");
return;
}
// 主要修改這裏,不先獲取響應結果
// 初始化響應結果
String feedback = null;
while (true) {
if (feedback != null) {
if (feedback.equals("PassWord Wrong!")) {
System.out.println("PassWord Wrong!");
} else if (feedback.equals("Registration Successful!")) {
System.out.println("Registration Successful!");
break;
}
}
System.out.println("輸入密碼:");
// 輸入密碼
Scanner scanner = new Scanner(System.in);
OutputStream outputStream = socket.getOutputStream();
String password = scanner.nextLine();
outputStream.write(password.getBytes());
feedback = bufferedReader.readLine();
}
// 關閉連接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
成功實現!
總結
這次的實驗給我提了個醒,看似簡單的東西,也永遠不要輕視它。只有拿出應有的實例去解決問題,問題纔是你眼中那個簡單的問題。
後注:在瀏覽網上他人實現的時候,發現有用多線程來實現的,後面我也會對這篇文章做出更新,將多線程的升級版實現與大家分享。