java 網路 socket TCP / UDP / catch 語句塊捕捉到異常後,繼續執行語句塊後面的程式碼
阿新 • • 發佈:2019-02-04
java 網路 socket TCP / server 端
package test.java.Net; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.net.*; /** * * @author jalo * 如果是客戶端和服務端互動讀寫的話,兩方必須,有一個先寫後讀,有一個先讀後寫 */ public class TCPServer { //在網路應用程式的編寫中,server / client一塊寫。在啟動的時候,也是首先起server,再起client public static void main(String args[]) throws IOException { System.out.println("server"); ServerSocket ss = null; try { ss = new ServerSocket(6666); } catch (IOException e) { System.out.println("不能監聽埠" + e); System.exit(0);//如果寫的嚴謹一點,這裡應該系統退出,不繼續往下執行//catch 丟擲異常,直接執行後面catch 語句塊後面的語句 } //server的應用程式往往是不間斷的在執行,他在等待著客戶端的連線。 //客戶端一連上,他才會執行。這是阻塞式連線。這句話完成,這個埠已經監聽。這時我們寫client 端 ////////////////client 端已經申請連線我了,我server 是不是接收這個連線請求還是個問題 while(true){//以下幾句如果不加while(true),那隻能接受一個連線。有了,則連一個我列印一個,然後再等待下一個。這才是真正的server,7*24*365 Socket s = ss.accept(); //accept 這個方法是阻塞式的,到這就停止,如果沒有任何客戶端連上來,他就在那傻傻的不動 //,socket 叫做和client 端的一個連線,accept是接受的意思。這個方法的作用: //作為一個伺服器端來說,他可以接收很多很多客戶端的連線,如圖1中server 端新建的紅色socket 。 System.out.println("accept "); InputStream is = s.getInputStream(); //我這個s(socket) 就是連著客戶端的socket,所以我這裡拿著的輸入管道就是客戶端的輸出管道 //這是一個連線,所以是一根管道 DataInputStream dis = new DataInputStream(is); //s.getInetAddress(),s.getPort() ,也就是返回的客戶端IP,port,Returns the address to which the socket is connected. System.out.println("A client connect , it says "+dis.readUTF());//readUTF()也是阻塞式的(這裡也可以放.readLine()即也是阻塞式的),如果對方不寫 dis.close(); //東西過來,我也在這傻傻等著,一直對方寫東西過來為止。這個方法阻塞住,不能再接收其他的client 連線請求 s.close(); //這些都是同步式的,所以不好,但是java 已經推出了非同步式的網路程式設計,意思是我accept() 之後就相當於 //註冊一下,然後我就走了,我該幹什麼幹什麼,什麼時候就客戶端連上,系統通知我,我再連上,這就叫非同步式。這才是效率最高的。 //非同步IO,VC裡面,這種網路程式設計的模型巨多無比,有最底層的,有用windows 自己提供的API 介面的,有用同步式的 /非同步式的,還有一種最有效率的 //叫做iocompletionport,(io 完成介面,)不僅是非同步式的,而且還有一個執行緒池在不停等待,只要cpu 多,那麼處理的吞吐量就會特別大 //就是同時有好多人連線也沒什麼關係,java 1.6達打不到這個層次,但是既然java已經提供非同步式,那麼他就能處理很多很多的連線了。現在很多程式 //都是用java 編寫的TCP 的server,比如tomcat,jboss,也已經證明大量的連線可以執行在java 寫的server 上面。但是這不是將來我們工作的重點。 // } ///////////////一旦我們連上了,c 和 s 就通過管道來說話,通過流來說話 } }
java 網路 socket TCP / client 端
import java.io.DataOutputStream; import java.io.OutputStream; import java.net.*; public class TCPClient { public static void main(String args[]) throws Exception{ System.out.println("client"); //client 端這邊的插座叫什麼了?socket.服務端的叫serversocket Socket s = new Socket("127.0.0.1",6666);//127.0.0.1 叫本機IP,指定到你要連線到哪個埠上,server 那個埠,那邊有人在監聽6666 //這邊就連到6666 。這時候,client 這邊的埠,系統隨機選擇,沒必要我繫結在哪個埠上,再和你6666建立連線。 //反正只要咱們倆建立起來連線,你這個埠就永遠歸我所用。你server 再發別的東西,很顯然你發不到別的地方去,你就 //只能發到我client 端的這個埠上。 //////////////client 這端往外說,就是輸出流, OutputStream os = s.getOutputStream();//通過這個可以看出,如圖1,連線建立起來後,相當於有連線裡面有兩根管道,一根輸入 //一根輸出 DataOutputStream dos = new DataOutputStream(os); Thread.sleep(3000000); dos.writeUTF("hello server"); dos.flush(); dos.close(); s.close(); //socket 也是一個連線,說完話,也自己關掉,清理好。 } }
java 網路 socket UDP / server 端。嚴格意義上講,UDP 沒有server 和 client 的概念,因為他不區分客戶端的socket 和server 的socket
對於UDP來說,他的socket 也是插座,但是無線連線,不像TCP,需要連起來一個通道,才能發資料
udp server
package test.java.Net; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.nio.ByteBuffer; /** * * @author jalo * 如果接收的是long 型,有兩種方式,第一種是寫出端直接藉助ByteArrayOutputStream和DataOutputStream * 接收端直接用這個byte[]陣列去初始化ByteArrayInputStream,再包上一層DataInputStream,去readLong * 第二種是用本例中的byteArrayToLong(byte[])去轉化成long 型別 * */ public class udpserver { public static long byteArrayToLong(byte[] buf) { //long型別的前 ByteBuffer buffer = ByteBuffer.allocate(8); buffer.put(buf, 0, 8); buffer.flip();//need flip return buffer.getLong(); } public static void main(String[] args) throws IOException { // udpserver InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 40000);//注意這個是udp 的埠,udp 和tcp 不公用埠,他們都有40000埠 DatagramSocket ds = new DatagramSocket(isa); byte []buf = new byte[1024]; // 1024長度的byte陣列這個是1KB DatagramPacket packet = new DatagramPacket(buf, 1024); while(true){ ds.receive(packet);//也是阻塞式的方法。注意tcp是直接拿到流(因為有連線),在流上面包DataInputStream 即可實現各種型別的讀寫(readLong等) //UDP不行,UDP只能拿資料包,然後分析裡面的內容,如果是long,還得去轉化(通過ByteArrayInputStream(byte[])) String info = new String(buf,0,packet.getLength());//此時這裡是亂碼,因為傳過來的是long 型別,你給解析成string型別了 byte bufIn[] = new byte[1024]; ByteArrayInputStream bais = new ByteArrayInputStream(buf);// 可以用buf 直接 DataInputStream dis = new DataInputStream(bais); //long receiveLongVar = byteArrayToLong(buf); long receiveLongVar = dis.readLong(); System.out.println("receive is "+receiveLongVar+""+"接收位元組的長度為:"+packet.getLength() +"client 的埠是"+ds.getPort());//1024是資料包的大小,接收長度不是1024, } } }
udp client
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class udpclient {
public static void main(String[] args) throws IOException {
InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 40000);
DatagramSocket ds = new DatagramSocket(); //這個可以給引數,傳埠號,表示我 udp client 端的埠
//byte buf[] = "我是客戶端".getBytes();
/////////以下是傳送long 型別的方法,轉化成記憶體中的byte 陣列,其他型別也這樣操作即可,即藉助ByteArrayOutputStream,DataOutputStream
long l = 1132234599919232343L; //ByteArrayOutputStream此類實現了一個輸出流,其中的資料被寫入一個 byte 陣列。無論你寫什麼,最後都轉化成位元組陣列存在記憶體裡,這樣省空間
ByteArrayOutputStream baos = new ByteArrayOutputStream();// 這個是記憶體,是位元組陣列,但是具體大小不用管,直接往裡寫就寫
DataOutputStream dos = new DataOutputStream(baos);
dos.writeLong(l);//此時這個long 型別數已經被寫到位元組數組裡
byte buf1[] = baos.toByteArray(); //拿到記憶體中的byte 陣列,buf1.length是你有多少資料,length就多長
/////////
//System.out.println(String.valueOf(l).getBytes().length);//string 轉化成long型別,這是19位元組。如果按照long直接轉byte 陣列,則才8位元組(因為long本身是8位元組)
ds.send(new DatagramPacket(buf1, buf1.length,isa)); // 第二個引數是接收長度,注意第三個引數是InetSocketAddress
//為什麼TCP的時候,傳東西不需要ip + 埠,因為udp 無連線,你包給路由器,路由器總得知道,你這個包要到哪去。TCP有連線
//
}
}