在正式進入網絡編程之前先簡單介紹一個網絡編程的基本概念。
網絡編程就是兩個或多個設備之間的數據交換,其實更具體的說,網絡編程就是兩個或多個程序之間的數據交換即可以理解爲一次網絡通訊過程。在網絡通訊中,第一次主動發起通訊的程序被稱作客戶端(Client)程序,簡稱客戶端,而在第一次通訊中等待連接的程序被稱作服務器端(Server)程序,簡稱服務器。一旦通訊建立,則客戶端和服務器端完全一樣,沒有本質的區別。
由此,網絡編程中的兩種程序就分別是客戶端和服務器端,例如QQ程序,每個QQ用戶安裝的都是QQ客戶端程序,而QQ服務器端程序則運行在騰訊公司的機房中,爲大量的QQ用戶提供服務。這種網絡編程的結構被稱作客戶端/服務器結構,也叫做Client/Server結構,簡稱C/S結構。而一般如J2EE等web開發,則是瀏覽器/服務器,簡稱B/S結構。
使用B/S結構的程序,在開發時只需要開發服務器端即可,這種結構的優勢在於開發的壓力比較小,不需要維護客戶端。但是這種結構也存在着很多不足,例如瀏覽器的限制比較大,表現力不強,無法進行系統級操作等。
總之C/S結構和B/S結構是現在網絡編程中常見的兩種結構,B/S結構其實也就是一種特殊的C/S結構。
最後再介紹一個網絡編程中最重要,也是最複雜的概念——協議(Protocol)。按照前面的介紹,網絡編程就是運行在不同計算機中兩個程序之間的數據交換。在實際進行數據交換時,爲了讓接收端理解該數據,計算機比較笨,什麼都不懂的,那麼就需要規定該數據的格式,這個數據的格式就是協議。
那麼如何來編寫協議格式呢?答案是隨意。只要按照這種協議格式能夠生成唯一的編碼,按照該編碼可以唯一的解析出發送數據的內容即可。也正因爲各個網絡程序之間協議格式的不同,所以才導致了客戶端程序都是專用的結構。
在實際的網絡程序編程中,最麻煩的內容不是數據的發送和接收,因爲這個功能在幾乎所有的程序語言中都提供了封裝好的API進行調用,最麻煩的內容就是協議的設計以及協議的生產和解析,這個纔是網絡編程中最核心的內容。
在現有的網絡中,網絡通訊的方式主要有兩種:
1、 TCP(傳輸控制協議)方式
2、 UDP(用戶數據報協議)方式
關於這兩個協議的區別這裏不過多介紹。這裏我們採用TCP來進行傳輸。
在客戶端網絡編程中,首先需要建立連接,在Java API中以java.net.Socket類的對象代表網絡連接,所以建立客戶端網絡連接,也就是創建Socket類型的對象,該對象代表網絡連接,示例如下:
Socket socket1 = new Socket(“192.168.1.103”,10000);
Socket socket2 = new Socket(“www.sohu.com”,80);
注:Socket的參數一表示服務器ip地址或者域名或者主機名。(寫主機名獲取域名最後都被解析爲ip地址),參數二表示端口號。
連接一旦建立,則完成了客戶端編程的第一步,緊接着的步驟就是按照“請求-響應”模型進行網絡數據交換,在Java語言中,數據傳輸功能由Java IO實現,也就是說只需要從連接中獲得輸入流和輸出流即可,然後將需要發送的數據寫入連接對象的輸出流中,在發送完成以後從輸入流中讀取數據即可。示例代碼如下:
OutputStream os = socket1.getOutputStream(); //獲得輸出流
InputStream is = socket1.getInputStream(); //獲得輸入流
最後當數據交換完成以後,關閉網絡連接,釋放網絡連接佔用的系統端口和內存等資源,完成網絡操作,示例代碼如下:
socket1.close();
- 1
現在我們編寫一個完整客戶段的Demo來向服務器發送字符串 “Hello World”
public class SocketClient {
public static void main(String[] args) {
try{
//創建Socket實例
Socket socket = new Socket("192.168.1.8",8888);
//獲取輸出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,world".getBytes());
//釋放資源
outputStream.close();
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
服務端的Demo:
public class SocketService {
public static void main(String[] args) {
InputStream inputStream;
Socket socket;
StringBuilder s = new StringBuilder();
try {
//服務器端接收消息的類。定製端口號爲8888
ServerSocket serviceSocket = new ServerSocket(8888);
//獲取socket。這個方法是阻塞式的
socket = serviceSocket.accept();
inputStream = socket.getInputStream();
byte buf[] = new byte[1024];
int len = 0;
while((len=(inputStream.read(buf)))>0){
s.append(new String(buf,0,len));
}
//打印客戶端的消息
System.out.println(s.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
先運行服務端的Demo,在運行客戶端的。即可看到在服務端接受到了客戶端傳遞過來的字符串HelloWorld.
服務端接受到客戶端的信息後,向客戶端迴應一句話:
客戶端:
public class SocketClient {
public static void main(String[] args) {
Socket socket =null;
InputStream inputStream =null;
OutputStream outputStream =null;
try{
//創建Socket實例
socket = new Socket("hadoop",10000);
//獲取輸出流,向服務器發生數據
outputStream = socket.getOutputStream();
outputStream.write("hello world:".getBytes());
///獲取輸入流,獲取服務器的響應
inputStream = socket.getInputStream();
byte[] buff = new byte[1024];
int len = 0;
len = inputStream.read(buff);
//打印服務端的相應
System.out.println(new String(buff,0,len));
}catch(Exception e){
e.printStackTrace();
}finally {
//釋放資源
try {
inputStream.close();
outputStream.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
服務端:
public class SocketService {
public static void main(String[] args) {
InputStream inputStream =null;
OutputStream outputStream =null;
Socket socket = null;
ServerSocket serviceSocket =null;
try {
//服務器端接收消息的類。定製端口號爲8888
serviceSocket = new ServerSocket(10000);
//獲取socket。這個方法是阻塞式的
socket = serviceSocket.accept();
inputStream = socket.getInputStream();
byte buf[] = new byte[1024];
int len = 0;
len =inputStream.read(buf);
//打印客戶端的消息
System.out.println(new String(buf,0,len));
//向客戶端生成響應
outputStream = socket.getOutputStream();
outputStream.write("收到".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//釋放資源
try {
outputStream.close();
inputStream.close();
socket.close();
serviceSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}