前言
所謂Socket(套接字),就是對網(wǎng)絡(luò)中不同主機上的應(yīng)用進程之間進行雙向通信的端點的抽象。一個套接字就是網(wǎng)絡(luò)上進程通信的一端,提供了應(yīng)用層進程利用網(wǎng)絡(luò)協(xié)議交換數(shù)據(jù)的機制。從所處的地位來講,套接字上聯(lián)應(yīng)用進程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議進行通信的接口,是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧進行交互的接口。
套接字是通信的基石,是支持TCP/IP協(xié)議的路通信的基本操作單元??梢詫⑻捉幼挚醋鞑煌鳈C間的進程進行雙間通信的端點,它構(gòu)成了單個主機內(nèi)及整個網(wǎng)絡(luò)間的編程界面。
socket是什么?
一個數(shù)據(jù)包經(jīng)由應(yīng)用程序產(chǎn)生,進入到協(xié)議棧中進行各種報文頭的包裝,然后操作系統(tǒng)調(diào)用網(wǎng)卡驅(qū)動程序指揮硬件,把數(shù)據(jù)發(fā)送到對端主機。整個過程的大體的圖示如下。
Socket 相當于是應(yīng)用程序的大門,我們在網(wǎng)絡(luò)中發(fā)送的報文都會經(jīng)過這道大門才能夠進入到應(yīng)用程序中,讓應(yīng)用程序來使用報文中的數(shù)據(jù)。
要寫網(wǎng)絡(luò)程序就必須用Socket
- 通信的兩端要有Socket,是兩臺機器間通信的端點
- 網(wǎng)絡(luò)通信其實就是Socket間的通信
Java中的Socket
Socket允許程序把網(wǎng)絡(luò)連接當成一個流,數(shù)據(jù)在兩個Socket間通過IO傳輸,一般主動發(fā)起通信的應(yīng)用程序?qū)儆诳蛻舳?,等待通信請求的為服?wù)端。
Java中的網(wǎng)絡(luò)通信時通過Socket實現(xiàn)的,當我們需要通訊時(讀寫數(shù)據(jù))
-
socket.getOutputStream():獲取一個輸出流
-
socket.getInputStream():獲取一個輸入流
客戶端上的使用
- 客戶端的Socket對象上的getOutputStream方法得到的輸出流其實就是發(fā)送給服務(wù)器端的數(shù)據(jù)。
- 客戶端的Socket對象上的getInputStream方法得到輸入流其實就是從服務(wù)器端發(fā)回的數(shù)據(jù)。
服務(wù)器端上的使用
- 服務(wù)端的Socket對象上的getOutputStream方法得到的輸出流其實就是發(fā)送給客戶端的數(shù)據(jù)。
- 服務(wù)端的Socket對象上的getInputStream方法得到的輸入流其實就是從客戶端發(fā)送給服務(wù)器端的數(shù)據(jù)流。
Socket有兩種編程方式
- TCP編程(面向連接,可靠的)
- UDP編程(無連接,不可靠)
Socket工作流程圖:
Java實現(xiàn)網(wǎng)絡(luò)上傳文件
編寫一個服務(wù)端和一個客戶端,要求在某端口監(jiān)聽(端口可以自定義,前提是沒有被占用,否則會報錯)??蛻舳诉B接服務(wù)端,發(fā)送一張圖片(本地磁盤的圖片,可自定義);服務(wù)端收到客戶端發(fā)來的圖片,保存在服務(wù)端的項目工程目錄src中(保存位置可自定義),之后發(fā)送收到圖片并退出??蛻舳耸盏椒?wù)端發(fā)送的收到圖片,在退出。
注意:理論上服務(wù)端和客戶端的程序應(yīng)該是在不同的機器上的,這里為了方便,使用了一臺機器。所以使用了*InetAddress.getLocalHost() 獲取本機IP,這里可以修改為其他主機IP地址
這里說一下用的部分知識點,如有疑問請自行百度進行查看
-
InetAddress.getLocalHost():獲取本機的IP地址
-
serverSocket.accept():開始監(jiān)聽設(shè)置的端口,如果有連接則返回socket對象
-
BufferedOutputStream()和BufferedInputStream():字節(jié)處理流,包裝
-
OutputStreamWriter(OutputStream o):將字節(jié)輸出流轉(zhuǎn)換為字符輸出流
-
socket.shutdownInput()和socket.shutdownOutput分別為發(fā)送數(shù)據(jù)的輸入/輸出結(jié)束標記
-
注意:StreamUtils類是自定義的工具類,其中streamToByteArray是將文件輸入流轉(zhuǎn)換為字節(jié)數(shù)組文件數(shù)據(jù);streamToString將文件輸入流轉(zhuǎn)換為字符串數(shù)據(jù)(具體定義代碼在下方)
整體演示流程圖如下:
這里需要注意:如果使用字符流進行輸出,則需要刷新或關(guān)閉,才能寫入數(shù)據(jù)(此案例使用的字節(jié)流)
StreamUtils工具類
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 此類用于演示關(guān)于流的讀寫方法
*
*/
public class StreamUtils {
/**
* 功能:將輸入流轉(zhuǎn)換成byte[], 即可以把文件的內(nèi)容讀入到byte[]
* @param is
* @return
* @throws Exception
*/
public static byte[] streamToByteArray(InputStream is) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();//創(chuàng)建輸出流對象
byte[] b = new byte[1024];//字節(jié)數(shù)組
int len;
while((len=is.read(b))!=-1){//循環(huán)讀取
bos.write(b, 0, len);//把讀取到的數(shù)據(jù),寫入bos
}
byte[] array = bos.toByteArray();//然后將bos 轉(zhuǎn)成字節(jié)數(shù)組
bos.close();
return array;
}
/**
* 功能:將InputStream轉(zhuǎn)換成String
* @param is
* @return
* @throws Exception
*/
public static String streamToString(InputStream is) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder= new StringBuilder();
String line;
while((line=reader.readLine())!=null){
builder.append(line+"\r\n");
}
return builder.toString();
}
}
服務(wù)端文章來源:http://www.zghlxwxcb.cn/news/detail-464755.html
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
//服務(wù)端在本機監(jiān)聽9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//等待連接
Socket socket = serverSocket.accept();
//讀取客戶端發(fā)送的數(shù)據(jù),通過socket得到輸入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
socket.shutdownInput();
//將得到的bytes數(shù)組寫入到服務(wù)端的指定位置
String dest = "src\\test.png";
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(dest));
bufferedOutputStream.write(bytes);
//服務(wù)端給客戶端發(fā)送回復(fù)
bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
bufferedOutputStream.write("收到圖片".getBytes());
//字符流方式
// BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// bufferedWriter.write("收到圖片");
// bufferedWriter.flush();
// socket.shutdownOutput();
//關(guān)閉資源
System.out.println("關(guān)閉服務(wù)端");
bufferedOutputStream.close();
bufferedInputStream.close();
socket.close();
serverSocket.close();
// bufferedWriter.close();
}
}
客戶端文章來源地址http://www.zghlxwxcb.cn/news/detail-464755.html
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.net.InetAddress;
import java.net.Socket;
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
//客戶端連接服務(wù)端9999端口
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//創(chuàng)建讀取磁盤文件的輸入流
String file = "E:\\test.png";
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
//bytes就是對應(yīng)的字節(jié)數(shù)組
byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
//通過socket獲取到一個輸出流,將bytes數(shù)據(jù)發(fā)送到服務(wù)端
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
bufferedOutputStream.write(bytes);
socket.shutdownOutput();//寫入數(shù)據(jù)的一個結(jié)束標記
//接收服務(wù)端的回復(fù)
bufferedInputStream = new BufferedInputStream(socket.getInputStream());
String s = StreamUtils.streamToString(bufferedInputStream);
System.out.println(s);
socket.shutdownInput();
//關(guān)閉資源
System.out.println("關(guān)閉客戶端");
bufferedInputStream.close();
bufferedOutputStream.close();
socket.close();
}
}
到了這里,關(guān)于【網(wǎng)絡(luò)編程】Java中的Socket的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!