TCP傳輸
TCP傳輸是怎樣建立的呢?
- Socket和ServerSocket
- 建立客戶端和服務(wù)器端
- 建立連接后,通過Socket中的IO流進(jìn)行數(shù)據(jù)的傳輸
- 關(guān)閉socket
TCP傳輸客戶端與服務(wù)器端同樣是兩個獨(dú)立的應(yīng)用程序。
我們就來寫一個TCP輸出數(shù)據(jù)的程序。
TCP傳輸-客戶端
/*
* TCP協(xié)議發(fā)送數(shù)據(jù):
* A:創(chuàng)建發(fā)送端的Socket對象
* 這一步如果成功,就說明連接已經(jīng)建立成功了。
* B:獲取輸出流,寫數(shù)據(jù)
* C:釋放資源
*/
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建發(fā)送端的Socket對象
Socket s = new Socket("192.168.2.102", 8888);
// 獲取輸出流,寫數(shù)據(jù)
OutputStream os = s.getOutputStream();
os.write("TCP來了".getBytes());
// 釋放資源
s.close();
}
}
TCP傳輸-服務(wù)器
/*
* TCP協(xié)議接收數(shù)據(jù):
* A:創(chuàng)建接收端的Socket對象
* B:監(jiān)聽客戶端連接。返回一個對應(yīng)的Socket對象
* C:獲取輸入流,讀取數(shù)據(jù)顯示在控制臺
* D:釋放資源 */
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建接收端的Socket對象
ServerSocket ss = new ServerSocket(8888);
// 監(jiān)聽客戶端連接。返回一個對應(yīng)的Socket對象
Socket s = ss.accept(); // 偵聽并接受到此套接字的連接。此方法在連接傳入之前一直阻塞。
// 獲取輸入流,讀取數(shù)據(jù)顯示在控制臺
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
// 阻塞式方法
String str = new String(bys, 0, len);
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "---" + str);
// 釋放資源
s.close();
// ss.close(); //服務(wù)器一般不應(yīng)該關(guān)閉
}
}
這樣我們九建立了TCP協(xié)議傳輸數(shù)據(jù)的客戶端和服務(wù)器,運(yùn)行程序,服務(wù)器會收到客戶端發(fā)來的數(shù)據(jù),但是這樣的代碼,當(dāng)服務(wù)器端收到客戶端的數(shù)據(jù)時,客戶端并不知道,所以,我們就要給客戶端一個反饋了。
/* * 服務(wù)器端 */
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建服務(wù)器Socket對象
ServerSocket ss = new ServerSocket(11111);
// 監(jiān)聽客戶端的連接
Socket s = ss.accept(); // 阻塞
// 獲取輸入流
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys); // 阻塞
String server = new String(bys, 0, len);
System.out.println("server:" + server);
// 獲取輸出流
OutputStream os = s.getOutputStream(); o
s.write("數(shù)據(jù)已經(jīng)收到".getBytes());
// 釋放資源
s.close();
// ss.close();
}
}
/* * 客戶端 */
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建客戶端Socket對象
Socket s = new Socket("192.168.2.102",11111);
// 獲取輸出流
OutputStream os = s.getOutputStream();
os.write("雙十一快樂!".getBytes());
// 獲取輸入流
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);// 阻塞
String client = new String(bys, 0, len);
System.out.println("client:" + client);
// 釋放資源
s.close();
}
}
上傳文件
我們來完成通過TCP協(xié)議從客戶端上傳一個文件到服務(wù)器,并給出客戶端反饋文件上傳成功
/* * 上傳文件客戶端 */
public class UploadClient {
public static void main(String[] args) throws IOException {
// 創(chuàng)建客戶端Socket對象
Socket s = new Socket("192.168.2.102", 12345);
// 封裝文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 封裝通道內(nèi)流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
// 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
//Socket提供了一個終止,它會通知服務(wù)器你別等了,我沒有數(shù)據(jù)過來了
s.shutdownOutput();
// 接收反饋
BufferedReader brClient = new BufferedReader(new InputStreamReader( s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 釋放資源
br.close();
s.close();
}
}
/* * 上傳文件接收端(服務(wù)器) */
public class UploadServer {
public static void main(String[] args) throws IOException {
// 創(chuàng)建服務(wù)器端的Socket對象
ServerSocket ss = new ServerSocket(12345);
// 監(jiān)聽客戶端連接
Socket s = ss.accept();// 阻塞
// 封裝通道內(nèi)的流
BufferedReader br = new BufferedReader(new InputStreamReader( s.getInputStream()));
// 封裝文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); String line = null;
while ((line = br.readLine()) != null) {
// 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// 給出反饋
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter( s.getOutputStream()));
bwServer.write("文件上傳成功");
bwServer.newLine();
bwServer.flush();
// 釋放資源
bw.close();
s.close();
}
}
這是上傳文件并給出反饋的例子,我們再來看上傳圖片并給出反饋的例子怎么寫
上傳圖片
上傳圖片我們就要考慮不能用字符流了,要用字節(jié)流。
/* * 上傳圖片客戶端 */
public class UploadClient {
public static void main(String[] args) throws IOException {
// 創(chuàng)建客戶端Socket對象
Socket s = new Socket("192.168.2.102", 96320);
// 封裝圖片文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg"));
// 封裝通道內(nèi)的流
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
s.shutdownOutput(); // 讀取反饋
InputStream is = s.getInputStream();
byte[] bys2 = new byte[1024];
int len2 = is.read(bys2);
String client = new String(bys2, 0, len2);
System.out.println(client);
// 釋放資源
bis.close(); s.close();
}
}
/* * 上傳圖片接收端-服務(wù)器 */
public class UploadServer {
public static void main(String[] args) throws IOException {
// 創(chuàng)建服務(wù)器Socket對象
ServerSocket ss = new ServerSocket(96320);
// 監(jiān)聽客戶端連接
Socket s = ss.accept();
// 封裝通道內(nèi)流
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
// 封裝圖片文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg"));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
// 給一個反饋
OutputStream os = s.getOutputStream();
os.write("圖片上傳成功".getBytes());
bos.close();
s.close();
}
}
運(yùn)行程序,我們將客戶端a.jpg的圖片上傳到服務(wù)器后,服務(wù)器收到后會給我們返回圖片上傳成功
多并發(fā)上傳
在我們平時遇到的情況肯定不是一個客戶端對應(yīng)一個服務(wù)器,肯定是多個客戶端對應(yīng)一個服務(wù)器,那么就存在了多并發(fā)上傳,再大型項目中也要考慮服務(wù)器的負(fù)荷問題,那么我們就來用代碼實(shí)現(xiàn)一下當(dāng)多個用戶上傳文件到服務(wù)器時,我們應(yīng)該怎樣做?
如果我們還按照上面上傳文件的思路,去進(jìn)行多并發(fā)上傳,當(dāng)一個客戶端A建立連接之后,被服務(wù)端獲取到,服務(wù)端就在執(zhí)行代碼了,這個時候如果客戶端B建立連接只有等待客戶端A操作完成后它才能開始執(zhí)行,所以為了讓多個客戶端同時連接到服務(wù)器上傳代碼,我們就要運(yùn)用多線程技術(shù),把每個客戶端和服務(wù)器之間的連接封裝到一個線程中去,這樣就可以同時處理多個客戶端請求
/* * 服務(wù)器端 */
public class UploadServer {
public static void main(String[] args) throws IOException {
// 創(chuàng)建服務(wù)器Socket對象
ServerSocket ss = new ServerSocket(11111);
while (true) {
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}
/* * 并發(fā)的線程 */
public class UserThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
// 封裝通道內(nèi)的流
BufferedReader br = new BufferedReader(new InputStreamReader( s.getInputStream()));
// 為了防止名稱沖突,每次命名為隨機(jī)的
String newName = System.currentTimeMillis() + ".java"; BufferedWriter bw = new BufferedWriter(new FileWriter(newName)); String line = null;
while ((line = br.readLine()) != null) {
// 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// 給出反饋
BufferedWriter bwServer = new BufferedWriter( new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上傳成功");
bwServer.newLine();
bwServer.flush();
// 釋放資源
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
這樣就完成了多用戶上傳文件到客戶端了。