java服務端客戶端
要完成這個工作,需要完成三個部分的工作,以下依次說明:
一、建立伺服器類
Java中有一個專門用來建立Socket伺服器的類,名叫ServerSocket,可以用伺服器需要使用的埠號作為參數來創建伺服器對象。
ServerSocket server = new ServerSocket(9998)
這條語句創建了一個伺服器對象,這個伺服器使用9998號埠即在埠9998上注冊服務,這里稍微要注意的是埠的分配必須是唯一的。因為埠是為了唯一標識每台計算機唯一服務的,另外埠號是從0~65535之間的,前1024個埠已經被Tcp/Ip 作為保留埠,因此你所分配的埠只能是1024個之後的。當一個客戶端程序建立一個Socket連接,所連接的埠號為9998時,伺服器對象server便響應這個連接,並且server.accept()方法會創建一個Socket對象。伺服器端便可以利用這個Socket對象與客戶進行通訊。
Socket incoming = server.accept() ; // 監聽窗口,等待連接
進而得到輸入流和輸出流,並進行封裝
BufferedReader in = new BufferedReader(new
InputStreamReader(incoming.getInputStream()));
/*
當讀取文件時,先把內容讀到緩存中,當調用in.readLine()時,再從緩存中以字元的方式讀取數據(以下簡稱「緩存位元組讀取方式」)。
*/
PrintWriter ut = new PrintWriter(incoming.getOutputStream(),true);
隨後,就可以使用in.readLine()方法得到客戶端的輸入,也可以使用out.println()方法向客戶端發送數據。從而可以根據程序的需要對客戶端的不同請求進行回應。
在所有通訊結束以後應該關閉這兩個數據流,關閉的順序是先關閉輸出流,再關閉輸入流,即使用
out.close();
in.close();
二、建立客戶端代碼
相比伺服器端,客戶端要簡單一些,客戶端只需用伺服器所在機器的ip以及伺服器的埠作為參數創建一個Socket對象。得到這個對象後,就可以用"建立伺服器"部分介紹的方法實現數據的輸入和輸出。
Socket socket = new Socket("168.160.12.42",9998);
或:
Socket socket = new Socket(InetAddress.getLocalHost(),5678); // 向主機名為InetAddress.getLocalHost()的伺服器申請連接
客戶機必須知道有關伺服器的IP地址,對於著一點Java也提供了一個相關的類InetAddress 該對象的實例必須通過它的靜態方法來提供,它的靜態方法主要提供了得到本機IP 和通過名字或IP直接得到InetAddress的方法。
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
以上的程序代碼建立了一個Socket對象,這個對象連接到ip地址為168.160.12.42的主機上、埠為9998的伺服器對象。並且建立了輸入流和輸出流,分別對應伺服器的輸出和客戶端的寫入。
三、實例分析
服務方:
import java.io.*;
import java.net.*;
public class MyServer {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678); //在埠5678上注冊服務
Socket client=server.accept(); // 監聽窗口,等待連接
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedReader serverInput=new BufferedReader(new InputStreamReader(System.in));
PrintWriter ut=new PrintWriter(client.getOutputStream());
while(true){
String str=in.readLine(); //// 讀取從client傳來的數據信息
str = serverInput.readLine(); // 讀取用戶鍵盤輸入的字元串
System.out.println(str); //伺服器控制台輸出數據信息
out.println("has receive...."); //伺服器向客戶端發送信息:has receive....
out.flush();
if(str.equals("end"))
break;
}
client.close();
}
}
這個程序的主要目的在於伺服器不斷接收客戶機所寫入的信息只到,客戶機發送"End"字元串就退出程序,並且伺服器也會做出"Receive"為回應,告知客戶機已接收到消息。
客戶機代碼:
import java.net.*;
import java.io.*;
public class Client{
static Socket server;
public static void main(String[] args)throws Exception{
server=new Socket(InetAddress.getLocalHost(),5678); // 向主機名為InetAddress.getLocalHost()的伺服器申請連接
BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); //客戶端建立輸入流並進行封裝
PrintWriter ut=new PrintWriter(server.getOutputStream());
BufferedReader wt=new BufferedReader(new InputStreamReader(System.in)); //客戶端從鍵盤輸入信息
while(true){
String str=wt.readLine(); //客戶端讀取(獲得)鍵盤的字元串
String str1=in.readLine(); // 從伺服器獲得字元串
out.println(str); //客戶端向伺服器發送信息
out.flush();
if(str.equals("end")){
break;
}
System.out.println(in.readLine());
}
server.close();
}
}
客戶機代碼則是接受客戶鍵盤輸入,並把該信息輸出,然後輸出"End"用來做退出標識。
這個程序只是簡單的兩台計算機之間的通訊,如果是多個客戶同時訪問一個伺服器呢?你可以試著再運行一個客戶端,結果是會拋出異常的。那麼多個客戶端如何實現呢?
其實,簡單的分析一下,就可以看出客戶和服務通訊的主要通道就是Socket本身,而伺服器通過accept方法就是同意和客戶建立通訊.這樣當客戶建立Socket的同時。伺服器也會使用這一根連線來先後通訊,那麼既然如此只要我們存在多條連線就可以了。那麼我們的程序可以變為如下:
伺服器:
import java.io.*;
import java.net.*;
public class MyServer {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket(5678);
while(true){
Socket client=server.accept();
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter ut=new PrintWriter(client.getOutputStream());
while(true){
String str=in.readLine();
System.out.println(str);
out.println("has receive....");
out.flush();
if(str.equals("end"))
break;
}
client.close();
}
}
}
這里僅僅只是加了一個外層的While循環,這個循環的目的就是當一個客戶進來就為它分配一個Socket直到這個客戶完成一次和伺服器的交互,這里也就是接受到客戶的"End"消息.那麼現在就實現了多客戶之間的交互了。但是.問題又來了,這樣做雖然解決了多客戶,可是是排隊執行的。也就是說當一個客戶和伺服器完成一次通訊之後下一個客戶才可以進來和伺服器交互,無法做到同時服務,那麼要如何才能同時達到既能相互之間交流又能同時交流呢?很顯然這是一個並行執行的問題了。所以線程是最好的解決方案。
那麼下面的問題是如何使用線程.首先要做的事情是創建線程並使得其可以和網路連線取得聯系。然後由線程來執行剛才的操作,要創建線程要麼直接繼承Thread要麼實現Runnable介面,要建立和Socket的聯系只要傳遞引用就可以了.而要執行線程就必須重寫run方法,而run方法所做的事情就是剛才單線程版本main所做的事情,因此我們的程序變成了這樣:
import java.net.*;
import java.io.*;
public class MultiUser extends Thread{
private Socket client;
public MultiUser(Socket c){
this.client=c;
}
public void run(){
try{
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter ut=new PrintWriter(client.getOutputStream());
//Mutil User but can't parallel
while(true){
String str=in.readLine();
System.out.println(str);
out.println("has receive....");
out.flush();
if(str.equals("end"))
break;
}
client.close();
}catch(IOException ex){
}finally{
}
}
public static void main(String[] args)throws IOException{
ServerSocket server=new ServerSocket(5678);
while(true){
//transfer location change Single User or Multi User
MultiUser mu=new MultiUser(server.accept());
mu.start();
}
}
}
我的類直接從Thread類繼承了下來.並且通過構造函數傳遞引用和客戶Socket建立了聯系,這樣每個線程就有了。一個通訊管道.同樣我們可以填寫run方法,把之前的操作交給線程來完成,這樣多客戶並行的Socket就建立起來了。
『貳』 JAVA程序完成伺服器和客戶端的SOCKET通訊,要求伺服器使用多線程接收和處理多個客戶端訪問請求
1. 客戶端程序
import java.io.*;
import java.net.*;
public class TalkClient {
public static void main(String args[]) {
try{
Socket socket=new Socket("127.0.0.1",4700);
//向本機的4700埠發出客戶請求
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標准輸入設備構造BufferedReader對象
PrintWriter os=new PrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,並構造PrintWriter對象
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,並構造相應的BufferedReader對象
String readline;
readline=sin.readLine(); //從系統標准輸入讀入一字元串
while(!readline.equals("bye")){
//若從標准輸入讀入的字元串為 "bye"則停止循環
os.println(readline);
//將從系統標准輸入讀入的字元串輸出到Server
os.flush();
//刷新輸出流,使Server馬上收到該字元串
System.out.println("Client:"+readline);
//在系統標准輸出上列印讀入的字元串
System.out.println("Server:"+is.readLine());
//從Server讀入一字元串,並列印到標准輸出上
readline=sin.readLine(); //從系統標准輸入讀入一字元串
} //繼續循環
os.close(); //關閉Socket輸出流
is.close(); //關閉Socket輸入流
socket.close(); //關閉Socket
}catch(Exception e) {
System.out.println("Error"+e); //出錯,則列印出錯信息
}
}
}
2. 伺服器端程序
import java.io.*;
import java.net.*;
import java.applet.Applet;
public class TalkServer{
public static void main(String args[]) {
try{
ServerSocket server=null;
try{
server=new ServerSocket(4700);
//創建一個ServerSocket在埠4700監聽客戶請求
}catch(Exception e) {
System.out.println("can not listen to:"+e);
//出錯,列印出錯信息
}
Socket socket=null;
try{
socket=server.accept();
//使用accept()阻塞等待客戶請求,有客戶
//請求到來則產生一個Socket對象,並繼續執行
}catch(Exception e) {
System.out.println("Error."+e);
//出錯,列印出錯信息
}
String line;
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,並構造相應的BufferedReader對象
PrintWriter os=newPrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,並構造PrintWriter對象
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標准輸入設備構造BufferedReader對象
System.out.println("Client:"+is.readLine());
//在標准輸出上列印從客戶端讀入的字元串
line=sin.readLine();
//從標准輸入讀入一字元串
while(!line.equals("bye")){
//如果該字元串為 "bye",則停止循環
os.println(line);
//向客戶端輸出該字元串
os.flush();
//刷新輸出流,使Client馬上收到該字元串
System.out.println("Server:"+line);
//在系統標准輸出上列印讀入的字元串
System.out.println("Client:"+is.readLine());
//從Client讀入一字元串,並列印到標准輸出上
line=sin.readLine();
//從系統標准輸入讀入一字元串
} //繼續循環
os.close(); //關閉Socket輸出流
is.close(); //關閉Socket輸入流
socket.close(); //關閉Socket
server.close(); //關閉ServerSocket
}catch(Exception e){
System.out.println("Error:"+e);
//出錯,列印出錯信息
}
}}
『叄』 可不可以用php編寫伺服器,用java編寫客戶端
可以的,這兩種需要都既可以客戶端又可以服務端,但是建議Java作為服務端,PHP做客戶端