使用I/O流作為網路間傳輸資訊的工具並使用套件import java.net
TCP/IP
為連接性的通訊協定,分別有client端,server端
並且以I/O stream為溝通管道,以byte為單位
Socket 類別
通常為client端用來連接server端的工具
socket可以透過TCP/IP連接一些常用的Internet服務,用來取得所需資訊
建立socket物件
1.
Socket s=new Socket(String, int); //IP number , port number
2.
InetAddress serverIP=InetAddress.getByName("URL"); //會分析URL轉成IP位址
Socket s=new Socket(InetAddress, int);
取得資料
InputStream is= s.getInputStream(); //is物件可以從socket物件s中取得資訊流
OutputStream os= s.getOutputStream(); //os物件可以將資訊流寫入socket物件s
ServerSocket 類別
通常為伺服器端用來接收client端特定port的平台
創立port 9999的伺服器接收平台
ServerSocket server= new ServerSocket(9999);
while(true){
Socket socket= server.accept(); //接收到client端的socket
......
}
< I/O流的觀念 >
inputstream跟outputstream之間要有buffer緩衝, 不能直接兩者傳訊
實例
Client:
- 要知道連接server端的ip,port number
- 建立socket以用來連接server端
- 以I/O流發送訊息或是請求
import java.io.OutputStream;
import java.net.*;
//客戶端
public class Client{
public static void main(String args[]){
Socket socket=null;
OutputStream os=null;
try {
//1.要知道server端的ip以及port number
InetAddress serverIP=InetAddress.getByName("127.0.0.1");
int port = 9999;
//2.創立socket連接口
socket=new Socket(serverIP,port);
//3.以I/O流發送訊息
os= socket.getOutputStream();
os.write("你好這是來自client端的資訊!".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
finally{
if(os!=null){
try{
os.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(socket!=null){
try{
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
server端:
- server開啟要聆聽的port
- 等待client端連進此port
- 以I/O流讀取client端的訊息
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//伺服器端
public class Server{
public static void main(String args[]){
ServerSocket serverSocket=null;
Socket socket=null;
InputStream is=null;
ByteArrayOutputStream baos=null;
try {
//1.server開啟要聆聽的port
serverSocket=new ServerSocket(9999);
//2.等待client端連接過來,也就是client端的socket!
socket= serverSocket.accept();
//3.讀取客戶端的消息
is= socket.getInputStream();
//stream
baos=new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
} catch (Exception e) {
e.printStackTrace();
}
finally{
if(baos!=null){
try{
baos.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(is!=null){
try{
is.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(socket!=null){
try{
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(serverSocket!=null){
try{
serverSocket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
實例二 - 文建傳輸
1.我們首先啟用server, server端等待client端對接 <卡在serverSocket.accept()>
2.client端啟動
3.server端對接到client端資訊
client
import java.io.*;
import java.net.*;
public class File_Client {
public static void main(String args[]) throws Exception{
//1. 創立socket
Socket socket =new Socket(InetAddress.getByName("127.0.0.1"),9000);
//2. 創立output stream
OutputStream os=socket.getOutputStream();
//3. 文件流
FileInputStream fis=new FileInputStream(new File("monkey.jpg"));
//4. 寫出文件
byte[] buffer=new byte[1024];
int len;
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//關閉資源
fis.close();
os.close();
socket.close();
}
}
server
import java.io.*;
import java.net.*;
public class File_Server{
public static void main(String args[]) throws Exception{
//1. 創立服務端口
ServerSocket serverSocket=new ServerSocket(9000);
//2. 監聽客戶端的連接
Socket socket=serverSocket.accept(); //一直迴圈直到接收到
//3. 獲取客戶端輸出流
InputStream is= socket.getInputStream();
//4. 文件輸出
FileOutputStream fos=new FileOutputStream(new File("receive.jpg"));
byte[] buffer=new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//5. 關閉資源
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
但是其實還是有點問題,例如客戶端應該要確定伺服器端對接到訊息才斷開
而伺服器端也要回覆客戶端已經接收完畢
客戶端
import java.io.*;
import java.net.*;
public class File_Client {
public static void main(String args[]) throws Exception{
//1. 創立socket
Socket socket =new Socket(InetAddress.getByName("127.0.0.1"),9000);
//2. 創立output stream
OutputStream os=socket.getOutputStream();
//3. 文件流
FileInputStream fis=new FileInputStream(new File("monkey.jpg"));
//4. 寫出文件
byte[] buffer=new byte[1024];
int len;
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//5. 通知服務端已經傳輸完了
socket.shutdownOutput(); //client端傳輸完畢
//6. 確定server端成功對接才斷開連線
InputStream inputstream=socket.getInputStream();
//String byte[]
ByteArrayOutputStream baso=new ByteArrayOutputStream();
byte[] buffer2=new byte[1024];
int len2;
while((len2=inputstream.read(buffer2))!=-1){
baso.write(buffer2,0,len2);
}
System.out.println(baso.toString());
//關閉資源
baso.close();
inputstream.close();
fis.close();
os.close();
socket.close();
}
}
伺服器端
import java.io.*;
import java.net.*;
public class File_Server{
public static void main(String args[]) throws Exception{
//1. 創立服務端口
ServerSocket serverSocket=new ServerSocket(9000);
//2. 監聽客戶端的連接
Socket socket=serverSocket.accept(); //一直迴圈直到接收到
//3. 獲取客戶端輸出流
InputStream is= socket.getInputStream();
//4. 文件輸出
FileOutputStream fos=new FileOutputStream(new File("receive.jpg"));
byte[] buffer=new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//5. 通知客戶端成功對接
OutputStream os= socket.getOutputStream();
os.write("connect successful!".getBytes());
// 關閉資源
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
<問題與討論>
1.其實client/server的區分並非是用誰是資料給予方(server) 誰是資料接收方(client)
而是client是發出連線請求的端點, server是接收連線請求的端點,至於連線之後資料要由誰給誰都行,此混淆的觀念要注意
- 寫出文件的程式碼說明:
資訊在socket中的stream傳遞時其實都是採用byte的資料格式傳輸
因此假設你要將資料由socket傳遞給server端
或是需要print顯示傳過來的資訊,都要將資料內容(byte)寫進outputstream
<情況1>
byte[] buffer=new byte[1024];
int len;
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
<情況2>
byte[] buffer2=new byte[1024];
int len2;
while((len2=inputstream.read(buffer2))!=-1){
baso.write(buffer2,0,len2);
}
System.out.println(baso.toString());
inputstream.read(buffer) 會將inputstream資料流存進buffer,並且返回buffer存完資料後的內容長度
再由outputstream os寫入buffer存下的資訊
爾後os可以用作socket outputstream傳輸或是print顯示
inputstream --> buffer(byte[])
len=fis.read(buffer)
buffer(byte[]) --> outputstream
os.write(buffer,0,len);
UDP
沒有client/server的概念,只有簡單分為接收端與傳輸端:
- socket在兩者間沒有分別
- 傳送者不在乎是否有成功對接
- 傳給他人的封包跟從他人那邊接收的封包,都是是DatagramPacket物件處理
DatagramSocket 類別
不論是sender,receiver 都要建立
DatagramSocket socket = new DatagramSocket(port number)
DatagramPacket 類別
不論是sender,receiver 都要建立
sender是用來傳送, 一開始創立就有內容
DatagramPacket packet =DatagramPacket(str.getByte(),str.length(),IPadrress,port);
senderSocket.send(packet);
sendSocket.close();
receiver用來接收,因為一開始創立的物件是沒內容的,要先建立緩衝空間
byte[] buffer =new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,1024); //空
receiverSocket.receive(packet) //將獲取資料寫進packet
String str= new String(packet.getData(),0,packet.length);
System.out.println(str);
receiverSocket.close();
範例
傳輸端
import java.net.*;
public class UDPclient {
public static void main(String args[]) throws Exception{
//1. 創立一個socket
DatagramSocket socket=new DatagramSocket();
//2. 建立package
String msg="the message to server!";
InetAddress localhost= InetAddress.getByName("localhost");
int port= 9090;
//打包 (包裡的東西 給誰)
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);
//3. send package
socket.send(packet); //沒人對接也不管
//4. 關閉資源
socket.close();
}
}
接收端
import java.io.*;
import java.net.*;
//還是要等待客戶端的連接
public class UDPserver {
public static void main(String args[]) throws Exception{
//1. 開放端口
DatagramSocket socket =new DatagramSocket(9090);
//2. 接收package
byte[] buffer=new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0,buffer.length);
socket.receive(packet); //loop直到接收
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
//3. 關閉資源
socket.close();
}
}
單邊聊天室實作
sender可以一直傳訊息給receiver,直到特殊條件後停止
sender
import java.io.*;
import java.net.*;
public class UDPchat_sender {
public static void main(String args[]) throws Exception{
DatagramSocket socket=new DatagramSocket(9000);
//將輸入值打包成數據
BufferedReader reader= new BufferedReader(new InputStreamReader(System.in));
while(true){
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0, datas.length,new InetSocketAddress("localhost", 9001));
socket.send(packet);
if(data.equals("bye")) break;
}
socket.close();
}
}
receiver
import java.net.*;
public class UDPchat_receiver {
public static void main(String args[]) throws Exception{
DatagramSocket socket = new DatagramSocket(9001);
while(true){
byte[] input= new byte[1024];
DatagramPacket packet =new DatagramPacket(input,0,input.length);
socket.receive(packet);
byte[] datas=packet.getData();
String receiveData=new String(datas,0,datas.length);
System.out.println(receiveData);
if(receiveData.equals("bye")) break;
}
socket.close();
}
}
java 11 12影片等補完thread後來看