最近學了學Java Socket方面的東西,網上找了很多朋友的代碼參考了,做了兩個小例子,為資料使用。
一,網絡程式設計中兩個主要的問題:
一個是如何準确的定位網絡上一台或多台主機,另一個就是找到主機後如何可靠高效的進行資料傳輸。
在TCP/IP協定中IP層主要負責網絡主機的定位,資料傳輸的路由,由IP位址可以唯一地确定Internet上的一台主機。
而TCP層則提供面向應用的可靠(tcp)的或非可靠(UDP)的資料傳輸機制,這是網絡程式設計的主要對象,一般不需要關心IP層是如何處理資料的。
目前較為流行的網絡程式設計模型是客戶機/伺服器(C/S)結構。即通信雙方一方作為伺服器等待客戶提出請求并予以響應。客戶則在需要服務時向伺服器提 出申請。伺服器一般作為守護程序始終運作,監聽網絡端口,一旦有客戶請求,就會啟動一個服務程序來響應該客戶,同時自己繼續監聽服務端口,使後來的客戶也 能及時得到服務。
二,兩類傳輸協定:TCP;UDP:
TCP是Tranfer Control Protocol的 簡稱,是一種面向連接配接的保證可靠傳輸的協定。通過TCP協定傳輸,得到的是一個順序的無差錯的資料流。發送方和接收方的成對的兩個socket之間必須建 立連接配接,以便在TCP協定的基礎上進行通信,當一個socket(通常都是server socket)等待建立連接配接時,另一個socket可以要求進行連接配接,一旦這兩個socket連接配接起來,它們就可以進行雙向資料傳輸,雙方都可以進行發送 或接收操作。
UDP是User Datagram Protocol的簡稱,是一種無連接配接的協定,每個資料報都是一個獨立的資訊,包括完整的源位址或目的位址,它在網絡上以任何可能的路徑傳往目的地,是以能否到達目的地,到達目的地的時間以及内容的正确性都是不能被保證的。
UDP:
1,每個資料報中都給出了完整的位址資訊,是以無需要建立發送方和接收方的連接配接。
2,UDP傳輸資料時是有大小限制的,每個被傳輸的資料報必須限定在64KB之内。
3,UDP是一個不可靠的協定,發送方所發送的資料報并不一定以相同的次序到達接收方
TCP:
1,面向連接配接的協定,在socket之間進行資料傳輸之前必然要建立連接配接,是以在TCP中需要連接配接時間。
2,TCP傳輸資料大小限制,一旦連接配接建立起來,雙方的socket就可以按統一的格式傳輸大的資料。
3,TCP是一個可靠的協定,它確定接收方完全正确地擷取發送方所發送的全部資料。
了解Java Socket:
所謂socket通常也稱作"套接字",用于描述IP位址和端口,是一個通信鍊的句柄。應用程式通常通過"套接字"向網絡送出請求或者應答網絡請求。
網絡上的兩個程式通過一個雙向的通訊連接配接實作資料的交換,這個雙向鍊路的一端稱為一個Socket。Socket通常用來實作客戶方和服務方的連接配接。Socket是TCP/IP協定的一個十分流行的程式設計界面,一個Socket由一個IP位址和一個端口号唯一确定。
但是,Socket所支援的協定種類也不光TCP/IP一種,是以兩者之間是沒有必然聯系的。在Java環境下,Socket程式設計主要是指基于TCP/IP協定的網絡程式設計。
Socket通訊的過程:
Server端Listen(監聽)某個端口是否有連接配接請求,Client端向Server 端發出Connect(連接配接)請求,Server端向Client端發回Accept(接受)消息。一個連接配接就建立起來了。Server端和Client 端都可以通過Send,Write等方法與對方通信。
通常Socket通信包括四個步驟:
1、建立Socket。
2、打開連接配接到Socket的輸入/出流。
3、按照一定的協定對Socket進行讀/寫操作。
4、關閉Socket.(在實際應用中,并未使用到顯示的close,雖然很多文章都推薦如此,不過在我的程式中,可能因為程式本身比較簡單,要求不高,是以并未造成什麼影響。
下面做了兩個例子:一個是單線程的Socket通信,二個是多線程的Socket通信
單線程:
package com.zyujie.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerApp {
public static void main(String[] args) throws IOException {
//建立服務端,監聽端口6688,端口号是從0~65535之間的,socket的端口最好是1024以上。1024之前的端口已經被Tcp/Ip 作為保留端口
ServerSocket server = new ServerSocket(6688);
//接受到一個連接配接,并且傳回一個用戶端的Socket對象執行個體
Socket client = server.accept();
//原始的位元組流來源于Socket的兩個方法.getInputStream()和getOutputStream()
//這裡我們建立緩沖,把原始的位元組流轉變為Unicode
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());
while (true) {
//一行一行的讀取用戶端消息
String str = in.readLine();
System.out.println(str);
//傳回消息給用戶端
out.println("服務端已收到消息...");
out.flush();
//伺服器端讀到end就結束Socket通信,監聽退出
if (str.equals("end")){
break;
}
}
//socket執行個體,連接配接關閉
client.close();
}
}
package com.zyujie.socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class ClientApp {
private static Socket server;
public static void main(String[] args) throws Exception {
//InetAddress是java.net包中的類,其靜态方法是得到本機IP和通過名字或IP直接得到InetAddress的方法
server = new Socket(InetAddress.getLocalHost(), 6688);
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter out = new PrintWriter(server.getOutputStream());
//控制台輸入字元串
BufferedReader wt = new BufferedReader(new InputStreamReader(System.in));
while (true) {
//一行一行的讀取控制台的輸入
String str = wt.readLine();
//發送給伺服器端
out.println(str);
out.flush();
if (str.equals("end")) {
break;
}
//讀取伺服器端傳回的消息
System.out.println(in.readLine());
}
//socket執行個體,連接配接關閉
server.close();
}
}
多線程的Socket通信,隻提供了服務端代碼,用戶端和單線程的一樣:
package com.zyujie.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer extends Thread {
private Socket client;
/*
* 構造函數,接收每一個socket執行個體
*/
public SocketServer(Socket socket) {
this.client = socket;
}
/*
* 線程執行方法
*/
public void run() {
try {
//這裡我們建立輸入和輸出的緩沖,把原始的位元組流轉變為Unicode
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());
while (true) {
//讀取用戶端消息
String str = in.readLine();
System.out.println(str);
//傳回給用戶端消息
out.println("服務端已收到消息...");
out.flush();
//遇到end就結束,這裡隻是結束單個用戶端的連接配接
if (str.equals("end")){
break;
}
}
//socket執行個體,連接配接關閉
client.close();
} catch (IOException ex) {
} finally {
}
}
/*
* 啟用線程方法實作多個使用者連接配接socket伺服器端.
*/
public static void main(String[] args) throws IOException {
//建立服務端,監聽端口6688
ServerSocket server = new ServerSocket(6688);
//使用伺服器端保持永久監聽狀态
while (true) {
//接收每一個用戶端的連接配接,并傳回socket執行個體
SocketServer ss = new SocketServer(server.accept());
//為每一個用戶端啟一個線程,去執行操作
ss.start();
}
}
}