推薦:Java網絡程式設計彙總
Java網絡程式設計-Socket程式設計初涉一(簡易用戶端-伺服器)
伺服器
伺服器的socket程式有以下幾個任務:
- 建立ServerSocket。
- 綁定端口。
- 監聽端口。
- 阻塞,等待用戶端連接配接。
- 與用戶端連接配接成功後,可以資料互動。
Java網絡程式設計-Socket簡介 伺服器socket程式:
package socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
final String QUIT = "QUIT";
final int DEFAULT_PORT = 8888;
ServerSocket serverSocket = null;
try {
// 綁定監聽端口
serverSocket = new ServerSocket(DEFAULT_PORT);
System.out.println("啟動伺服器,監聽端口"+DEFAULT_PORT);
while(true){
//等待用戶端連接配接
Socket socket = serverSocket.accept();
System.out.println("用戶端["+socket.getPort()+"]已連接配接");
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
String msg = null;
//讀取用戶端發送的消息,并且進行回複
while ((msg = reader.readLine()) != null){
System.out.println("用戶端["+socket.getPort()+"]:"+msg);
//回複用戶端
writer.write("伺服器:已收到-"+msg+"\n");
writer.flush();
// 檢視用戶端是否退出
if(QUIT.equalsIgnoreCase(msg)){
System.out.println("用戶端["+socket.getPort()+"]已退出");
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(serverSocket != null){
try {
serverSocket.close();
System.out.println("關閉serverSocket");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
建立socket、綁定端口、監聽端口
建立ServerSocket、綁定端口、監聽端口其實在我們的程式中,一行語句就實作了。
serverSocket = new ServerSocket(DEFAULT_PORT);
按住CTRL,進入該構造器。
源碼如下:
public ServerSocket(int port) throws IOException {
this(port, 50, null);
}
進入再次調用的構造器。
源碼如下:
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
setImpl();
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException(
"Port value out of range: " + port);
if (backlog < 1)
backlog = 50;
try {
bind(new InetSocketAddress(bindAddr, port), backlog);
} catch(SecurityException e) {
close();
throw e;
} catch(IOException e) {
close();
throw e;
}
}
進入
bind方法
。
源碼如下:
public void bind(SocketAddress endpoint, int backlog) throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
throw new SocketException("Already bound");
if (endpoint == null)
endpoint = new InetSocketAddress(0);
if (!(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type");
InetSocketAddress epoint = (InetSocketAddress) endpoint;
if (epoint.isUnresolved())
throw new SocketException("Unresolved address");
if (backlog < 1)
backlog = 50;
try {
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkListen(epoint.getPort());
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
bound = true;
} catch(SecurityException e) {
bound = false;
throw e;
} catch(IOException e) {
bound = false;
throw e;
}
}
其中有兩行語句如下:
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
很清楚了吧,程式調用了ServerSocket的構造器,建立了ServerSocket。
而該構造器間接實作了綁定端口、監聽端口(上面兩行語句)。
阻塞,等待用戶端連接配接
Socket socket = serverSocket.accept();
可以自己去看看源碼。
有用戶端連接配接成功後,會生成一個socket。
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
擷取向用戶端讀、寫的字元流。
Java IO體系的學習總結
String msg = null;
//讀取用戶端發送的消息,并且進行回複
while ((msg = reader.readLine()) != null){
System.out.println("用戶端["+socket.getPort()+"]:"+msg);
//回複用戶端
writer.write("伺服器:已收到-"+msg+"\n");
writer.flush();
// 檢視用戶端是否退出
if(QUIT.equalsIgnoreCase(msg)){
System.out.println("用戶端["+socket.getPort()+"]已退出");
break;
}
}
上面是伺服器讀取用戶端發送的消息的代碼,一行一行的讀取消息,并且隻有當用戶端發送
“quit”
給伺服器時,才表示此用戶端要退出,并且在這個過程中其他用戶端是不能與伺服器進行連接配接的,因為伺服器一直在
while
裡面讀取此用戶端發送的資料,不過,這隻是一個體驗版,以後會一步一步進行更新的,畢竟學習也是一步一步學出來的。
關閉資源
先不用糾結關閉資源的正确姿勢,這是課程中講師關閉資源的方法,等基礎比較好以後,我會自己去實踐一下,再進行總結,之後也會去閱讀源碼,寫相關部落格,現在的任務就是把整個流程搞明白即可,不去糾結細節,一層一層來揭開Java網絡程式設計的面紗。
serverSocket.close();
用戶端
用戶端的socket程式有以下幾個任務:
- 建立Socket。
- 連接配接伺服器。
- 與伺服器連接配接成功後,可以資料互動。
用戶端socket程式:
package socket;
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args){
final String QUIT = "QUIT";
final String DEFAULT_SERVER_HOST = "127.0.0.1";
final int DEFAULT_PORT = 8888;
Socket socket = null;
BufferedWriter writer = null;
try {
//建立socket
socket = new Socket(DEFAULT_SERVER_HOST , DEFAULT_PORT);
//建立IO流
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
//等待使用者輸入資訊
BufferedReader consoleReader = new BufferedReader(
new InputStreamReader(System.in));
while (true){
String input = consoleReader.readLine();
//發送消息給伺服器
writer.write(input+"\n");
writer.flush();
//讀取伺服器傳回的消息
String msg = reader.readLine();
System.out.println(msg);
// 檢視使用者是否退出
if (QUIT.equalsIgnoreCase(input)){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(writer != null){
try {
writer.close(); // 會自動flush()
System.out.println("關閉socket");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
建立Socket、連接配接伺服器
socket = new Socket(DEFAULT_SERVER_HOST , DEFAULT_PORT);
進入構造器。
源碼如下:
/**
* Creates a stream socket and connects it to the specified port
* number on the named host.
* <p>
* If the specified host is {@code null} it is the equivalent of
* specifying the address as
* {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
* In other words, it is equivalent to specifying an address of the
* loopback interface. </p>
* <p>
* If the application has specified a server socket factory, that
* factory's {@code createSocketImpl} method is called to create
* the actual socket implementation. Otherwise a "plain" socket is created.
* <p>
* If there is a security manager, its
* {@code checkConnect} method is called
* with the host address and {@code port}
* as its arguments. This could result in a SecurityException.
*
* @param host the host name, or {@code null} for the loopback address.
* @param port the port number.
*
* @exception UnknownHostException if the IP address of
* the host could not be determined.
*
* @exception IOException if an I/O error occurs when creating the socket.
* @exception SecurityException if a security manager exists and its
* {@code checkConnect} method doesn't allow the operation.
* @exception IllegalArgumentException if the port parameter is outside
* the specified range of valid port values, which is between
* 0 and 65535, inclusive.
* @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
* @see java.net.SocketImpl
* @see java.net.SocketImplFactory#createSocketImpl()
* @see SecurityManager#checkConnect
*/
public Socket(String host, int port)
throws UnknownHostException, IOException
{
this(host != null ? new InetSocketAddress(host, port) :
new InetSocketAddress(InetAddress.getByName(null), port),
(SocketAddress) null, true);
}
先不去看細節,先看注釋
Creates a stream socket and connects it to the specified port number on the named host.
。建立流套接字并将其連接配接到命名主機上的指定端口号。很顯然,用戶端調用Socket構造器,建立了Socket,并且連接配接了伺服器(伺服器已經運作的情況下)。
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
擷取向伺服器讀、寫的字元流。
//等待使用者輸入資訊
BufferedReader consoleReader = new BufferedReader(
new InputStreamReader(System.in));
等待使用者輸入資訊,并且是控制台的輸入
System.in
。
while (true){
String input = consoleReader.readLine();
//發送消息給伺服器
writer.write(input+"\n");
writer.flush();
//讀取伺服器傳回的消息
String msg = reader.readLine();
System.out.println(msg);
// 檢視使用者是否退出
if (QUIT.equalsIgnoreCase(input)){
break;
}
}
向伺服器發送消息,并且接收伺服器的回複,也是一行一行的讀取。
關閉資源
writer.close();
到這裡,我們便實作了一個簡易用戶端-伺服器編寫。