最近學到java的網絡編程,瞭解到java中對網絡編程提供了豐富的API,一般使用的有InetAddress類,URL類和URLConnection類,再就是使用很頻繁的socket類。
我們使用一個小示例,使用socket建立一個socket客戶端和socket服務器。看看能不能實現通信。
由於服務器對每一個鏈接的客戶端都要做出反應,因此用線程來循環監聽。
第一步寫一個線程類ServerThread,服務器需要提供的服務被封裝到這個類裏了:
public class ServerThread extends Thread {
//和本線程相關的socket
Socket socket = null;
public ServerThread(Socket socket){
this.socket = socket;
}
//線程需要執行的動作
public void run(){
InputStream is=null;
InputStreamReader isr=null;
BufferedReader br=null;
OutputStream os=null;
PrintWriter pw=null;
try {
//獲取輸入流,聆聽客戶端的請求
is = socket.getInputStream();
//獲取字節流
isr = new InputStreamReader(is);//獲取字符流
br = new BufferedReader(isr);//添加緩衝
String info = null;
while((info = br.readLine()) != null){//循環讀取客戶端的信息
System.out.println("我是服務器,客戶端說:"+info);
}
socket.shutdownInput();//關閉輸入流
//獲取輸出流,響應客戶端的請求。
os = socket.getOutputStream();//獲取字節流
pw = new PrintWriter(os);//包裝成打印流
pw.write("歡迎您!");
pw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally{
//關閉資源
try {
if(pw!=null) pw.close();
if(os!=null) os.close();
if(br!=null) br.close();
if(isr!=null) isr.close();
if(is!=null) is.close();
if(socket!=null) socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
第二步搭建socket服務器。給其指定一個端口(不用0—1023端口的原因是之間的端口是默認給系統佔用的),並保持監聽狀態,當客戶端鏈接上了會創建一個新線程做出行爲響應。新建類socket_server_test
public class Socket_server_test { public static void main(String[] args) { try { //1、創建一個服務器端的socket——serverSocket,指定綁定的端口,並監聽此端口 ServerSocket serverSocket = new ServerSocket(8888);//1023之前的端口不用 //2、調用accept()方法開始監聽,等待客戶端的鏈接 Socket socket=null; //記錄所連接的客戶端的數量 int count = 0; System.out.println("*********服務器即將啓動,等待客戶端鏈接**********"); //循環監聽端口並等待 while(true){ socket = serverSocket.accept(); ServerThread serverThread = new ServerThread(socket); serverThread.start(); count++;//統計連接人數,輸出客戶端數量 System.out.println("客戶端數量:"+count); InetAddress address = socket.getInetAddress(); System.out.println("當前客戶端的IP爲:"+address.getHostAddress()); } // serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
這樣我們再寫一個socket客戶端,如上述代碼所示,這個服務器端會獲取客戶端的IP信息~
新建類socket_client_test
public class Socket_client_test {
public static void main(String[] args) {
try {
//1、創建客戶端socket,指定服務器地址和端口
Socket socket = new Socket("localhost", 8888);
//2、獲取輸出流,向服務器發送信息。
OutputStream os = socket.getOutputStream();//字節輸出流
PrintWriter pw = new PrintWriter(os);//將輸出流包裝成打印流
pw.write("用戶名:user,密碼:123456");
pw.write(" ");
pw.write(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));//當前時間
pw.flush();
socket.shutdownOutput();
//3、獲取輸入流,並讀取服務器端的響應信息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while((info = br.readLine())!=null){
System.out.println("我是客戶端,服務器說:"+info);
}
//4、關閉其他資源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然後在運行時,需要先把server類運行,來爲client類提供服務,否則會報異常~server類運行後再運行client後,服務器控制檯和客戶端控制檯輸出不同
服務器端輸出(IP等信息是從客戶端發來的):
客戶端輸出(“歡迎你”是從服務器端發送來的話語):
在這個例子中,socket用accept()方法監聽端口,用getInputStream和getOutputStream兩個方法來獲取輸入流和輸出流。當然,服務結束後需要關閉相應的流。