UDP:
a) 將數據及源和目的封裝成數據包中,不需要建立連接
b) 每個數據報的大小限制在64K內
c) 因無連接,是不可靠協議
d) 不需要建立連接,速度快
TCP:
a) 建立連接,形成傳輸數據的通道
b) 在連接中進行大數據傳輸
c) 通過三次握手完成連接,是可靠協議
應用:
1,TCP在網絡通信上有極強的生命力,例如遠程連接(Telnet)和文件傳輸(FTP)都需要不定長度的數據被可靠地傳輸。但是可靠的傳輸是要付出代價的,對數據內容正確性的檢驗必然佔用計算機的處理時間和網絡的帶寬,因此TCP傳輸的效率不如UDP高。
2,UDP操作簡單,而且僅需要較少的監護,因此通常用於局域網高可靠性的分散系統中client/server應用程序。例如視頻會議系統,並不要求音頻視頻數據絕對的正確,只要保證連貫性就可以了,這種情況下顯然使用UDP會更合理一些。
基於Socket的java網絡編程
a) 就是爲網絡服務提供的一種機制
b) 通信的兩端都有Socket
c) 網絡通信其實就是socket間的通信
d) 數據在2個Socket間通過IO傳輸
1,什麼是Socket
網絡上的兩個程序通過一個雙向的通訊連接實現數據的交換,這個雙向鏈路的一端稱爲一個Socket。Socket通常用來實現客戶方和服務方的連接。Socket是TCP/IP協議的一個十分流行的編程界面,一個Socket由一個IP地址和一個端口號唯一確定。
但是,Socket所支持的協議種類也不光TCP/IP一種,因此兩者之間是沒有必然聯繫的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網絡編程。
2,Socket通訊的過程
Server端Listen(監聽)某個端口是否有連接請求,Client端向Server 端發出Connect(連接)請求,Server端向Client端發回Accept(接受)消息。一個連接就建立起來了。Server端和Client 端都可以通過Send,Write等方法與對方通信。
對於一個功能齊全的Socket,都要包含以下基本結構,其工作過程包含以下四個基本的步驟:
(1) 創建Socket;
(2) 打開連接到Socket的輸入/出流;
(3) 按照一定的協議對Socket進行讀/寫操作;
(4) 關閉Socket.(在實際應用中,並未使用到顯示的close,雖然很多文章都推薦如此,不過在我的程序中,可能因爲程序本身比較簡單,要求不高,所以並未造成什麼影響。)
3,創建Socket
創建Socket
java在包java.net中提供了兩個類Socket和ServerSocket,分別用來表示雙向連接的客戶端和服務端。這是兩個封裝得非常好的類,使用很方便。其構造方法如下:
Socket(InetAddress address, int port);
Socket(InetAddress address, int port, boolean stream);
Socket(String host, int prot);
Socket(String host, int prot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, int port, InetAddress localAddr,int localPort)
Socket(InetAddress address, int port, InetAddresslocalAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddressbindAddr)
其中address、host和port分別是雙向連接中另一方的IP地址、主機名和端口號,stream指明socket是流socket還是數據報socket,localPort表示本地主機的端口號,localAddr和 bindAddr是本地機器的地址(ServerSocket的主機地址),impl是socket的父類,既可以用來創建serverSocket又可 以用來創建Socket。count則表示服務端所能支持的最大連接數。
Socket client = new Socket("127.0.01.", 80);
ServerSocket server = new ServerSocket(80);
注意,在選擇端口時,必須小心。每一個端口提供一種特定的服務,只有給出正確的端口,才 能獲得相應的服務。0~1023的端口號爲系統所保留,例如http服務的端口號爲80,telnet服務的端口號爲21,ftp服務的端口號爲23, 所以我們在選擇端口號時,最好選擇一個大於1023的數以防止發生衝突。端口範圍:0-65535,其中0~1024系統使用或保留端口
在創建socket時如果發生錯誤,將產生IOException,在程序中必須對之作出處理。所以在創建Socket或ServerSocket是必須捕獲或拋出例外。
4,支持多客戶的client/server程序
前面的Client/Server程序只能實現Server和一個客戶的對話。在實際應用 中,往往是在服務器上運行一個永久的程序,它可以接收來自其他多個客戶端的請求,提供相應的服務。爲了實現在服務器方給多個客戶提供服務的功能,需要對上 面的程序進行改造,利用多線程實現多客戶機制。服務器總是在指定的端口上監聽是否有客戶請求,一旦監聽到客戶請求,服務器就會啓動一個專門的服務線程來響 應該客戶的請求,而服務器本身在啓動完線程之後馬上又進入監聽狀態,等待下一個客戶的到來。
5,簡單的Client/Server程序
獲得指定url的ip地址及名字
package com.wj.ip;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 得到ip地址
* @author wJing
* time:2014/2/9
*/
public class IPDemo1 {
/**
*
* @param args
* @throws Exception
*/
public staticvoid main(String[] args) throws Exception {
InetAddress i= InetAddress.getLocalHost();
System.out.println(i.toString());
System.out.println(i.getHostName());
System.out.println(i.getHostAddress());
InetAddressia = InetAddress.getByName("127.0.0.1");
System.out.println("address:"+ia.getHostAddress());
System.out.println("ip:"+ ia.getHostName());
}
}
簡單的Client(發送文本):
package com.wj.client;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
*
* @author wJing
* time:2014-2-915:09:54
* 把客戶端的一個文件傳遞到服務端,模擬
*/
public class TextClient {
public staticvoid main(String[] args) throws Exception, IOException {
Socket s =new Socket("localhost", 9999);
BufferedReaderbuf = new BufferedReader(new FileReader("d:\\abcde.txt"));
PrintWriterwriter = new PrintWriter(s.getOutputStream(),true);
/*
/////////////////////////////////////////////////////////////////
//時間戳,確定文件的結束標記
DataOutputStreamdos = new DataOutputStream(s.getOutputStream());
long time =System.currentTimeMillis();
dos.writeLong(time);
////////////////////////////////////////////////////////////////
*/
String line =null;
while((line =buf.readLine()) != null) {
writer.println(line);
}
//關閉客戶端輸出流
s.shutdownOutput();
////////////////////////////////////////////////////////
// writer.println(time);//文件讀完以後再發一次時間戳
///////////////////////////////////////////////////////////
BufferedReaderin = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str =in.readLine();
System.out.println(str);
buf.close();
s.close();
}
}
簡單的Server(接收文本):
package com.wj.server;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TextServer {
public staticvoid main(String[] args) throws Exception {
ServerSocketss = new ServerSocket(9999);
Socket s =ss.accept();
BufferedReaderbufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriterin = new PrintWriter(new FileWriter("e://copy.txt"),true);
/**
*
///////////////////////////////////////////////////////////
DataInputStreamdis = new DataInputStream(s.getInputStream());
long time =dis.readLong();
///////////////////////////////////////////////////////////
/**
* 方式1:發送一個標記給服務器
* 方式2:使用時間戳當作一個標記
* 方式3:使用socket的shutdowninput、shutdownoutput
*/
String line =null;
while((line =bufIn.readLine()) != null) {
// if(line.equals(time)){
// break;
// }
in.println(line);
}
PrintWriterout = new PrintWriter(s.getOutputStream(), true);
out.println("上傳成功");
in.close();
s.close();
ss.close();
}
}
簡單的Client(發送圖片):
package com.wj.client;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
/**
*
* @author wJing
* time:2014-2-916:38:57
* 上次圖片
*/
public class ImageClient {
public staticvoid main(String[] args) throws Exception, IOException {
Socket s =new Socket("localhost", 1520);
FileInputStreamfis = new FileInputStream("d:\\1.jpg");
OutputStreamout = s.getOutputStream();
byte[] buf =new byte[1024];
int len = 0;
while((len =fis.read(buf)) != -1) {
out.write(buf,0, len);
}
//告訴服務器數據已寫完
s.shutdownOutput();
InputStreamin = s.getInputStream();
byte[] bufIn= new byte[1024];
int num =in.read(bufIn);
System.out.println(newString(bufIn, 0, num));
fis.close();
s.close();
}
}
簡單的Server(接收圖片)
package com.wj.server;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
class picThread implements Runnable {
private Socket s;
publicpicThread(Socket s) {
this.s = s;
}
@Override
public void run(){
int count =1;
String ip =s.getInetAddress().getAddress().toString();
System.out.println(ip+ ".....connected");
try {
InputStreamin = s.getInputStream();
File file =new File(ip+count + ".jpg");
while(file.exists()){
file = newFile(ip + "(" + count++ + ").jpg");
}
FileOutputStreamfos = new FileOutputStream(file);
byte[] buf =new byte[1024];
int len = 0;
while((len =in.read(buf)) != -1) {
fos.write(buf,0, len);
}
OutputStreamout = s.getOutputStream();
out.write("上次成功".getBytes());
fos.close();
s.close();
}catch(Exception e) {
throw newRuntimeException(ip + "上傳失敗");
}
}
}
public class ImageServer {
public staticvoid main(String[] args) throws Exception {
// UploadPic();
//使用多線程處理多個客戶端的訪問
ServerSocketss = new ServerSocket(1520);
while(true) {
Socket s =ss.accept();
newThread(new picThread(s)).start();
}
}
//先線程的圖片上傳,一個客戶端連上以後只有等爲他服務完成以後才能爲下一個人服務
private staticvoid UploadPic() throws IOException, FileNotFoundException {
ServerSocketss = new ServerSocket(1520);
// while(true) {
Socket s =ss.accept();
InputStreamin = s.getInputStream();
FileOutputStreamfos = new FileOutputStream("e:\\server.jpg");
byte[] buf =new byte[1024];
int len = 0;
while((len =in.read(buf)) != -1) {
fos.write(buf,0, len);
}
OutputStreamout = s.getOutputStream();
out.write("上次成功".getBytes());
fos.close();
s.close();
// }
ss.close();
}
}
一個基於UDP的簡單聊天程序:
package com.wj.udp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
*
* @author wJing
*編寫一個聊天程序
*time:2014-2-9 11:33:20
*/
class Send implements Runnable {
privateDatagramSocket ds;
publicSend(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run(){
try {
BufferedReaderin = new BufferedReader(new InputStreamReader(System.in));
Stringline = null;
while((line= in.readLine()) != null) {
if("886".equals(line)){
break;
}
byte[] buf = line.getBytes();
DatagramPacketdp = new DatagramPacket(buf, buf.length,InetAddress.getByName("localhost"), 10002);
ds.send(dp);
}
} catch(Exception e) {
throw newRuntimeException("發送端失敗");
}
}
}
class Receive implements Runnable {
private DatagramSocketds;
publicReceive(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run(){
try {
while(true){
byte[]buf = new byte[1024 * 64];
DatagramPacketdp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
Stringip = dp.getAddress().getHostAddress();
Stringdata = new String(dp.getData(), 0, dp.getLength());
System.out.println("ip->"+ ip + ":" + data);
}
} catch(Exception e) {
throw newRuntimeException("接收失敗");
}
}
}
public class ChatDemo {
public staticvoid main(String[] args) throws Exception {
DatagramSocketsendSocket = new DatagramSocket();
DatagramSocketreceiveSocket = new DatagramSocket(10002);
newThread(new Send(sendSocket)).run();
newThread(new Receive(receiveSocket)).run();
}
}