# JAVA之旅(三十三)——TCP傳輸,互相(傷害)傳輸,復制文件,上傳圖片,多并發上傳,多并發登錄
* * *
> 我們繼續網絡編程
## 一.TCP
> 說完UDP,我們就來說下我們應該重點掌握的TCP了
* TCP傳輸?
* Socket和ServiceSocket
* 建立客戶端和服務端
* 建立連接后,通過Socket中的IO流進行數據的傳輸
* 關閉Socket
> 同樣的,我們的客戶端和服務端都是兩個獨立的應用
>
> 我們通過查閱API文檔發現,該對象在建立的時候,就可以去連接指定主機,因為tcp是面向連接的,所以在建立socket服務時,就要有服務存在,并成功連接,形成通路后,在該通道進行數據傳輸
>
> 所以我們用代碼來看下他的步驟
### 客戶端
~~~
package com.lgl.hellojava;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpClient {
public static void main(String[] args) {
try {
//1.創建客戶端的服務,傳地址和端口
Socket s = new Socket("192.168.1.102",10000);
//2.為了發送數據,應該獲得socket流中的輸出流
OutputStream out = s.getOutputStream();
out.write("你好".getBytes());
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
### 服務端
~~~
package com.lgl.hellojava;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 定義端點接收數據打印出來
* 服務端:
* 1.建立服務端的socket服務,servicesocket,并監聽一個端口
* 2.獲取連接過來的客戶端對象,通過accept方法,這個方法是阻塞的,沒有連接就會等
* 3.客戶端如果發過來數據,那么服務端要使用對應的客戶端對象,并獲取到該對象的讀取流
* 4.關閉服務端(可選操作)
* @author LGL
*
*/
public class TcpService {
public static void main(String[] args) {
try {
//1.建立連接,監聽端口
ServerSocket ss = new ServerSocket(10000);
//2.連接客戶端對象
Socket accept = ss.accept();
//獲取ip
String ip = accept.getInetAddress().getHostAddress();
//3.獲取客戶端發送過來的數據
InputStream in = accept.getInputStream();
//4.開始讀取
byte [] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
//5.關閉
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
## 二.TCP互相傳輸
> 我們在來寫一個實例去說明,他們的互訪動作,這里為了寫起來方便,就寫在一個類中了
~~~
package com.lgl.hellojava;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 客戶端發送信息,服務端收到,反饋信息
*
* @author LGL
*
*/
public class Tcp {
public static void main(String[] args) {
try {
Socket s = new Socket("192.168.1.102", 10005);
OutputStream out = s.getOutputStream();
out.write("我是客戶端".getBytes());
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf, 0, len));
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 服務端
* @author LGL
*
*/
class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf, 0, len));
OutputStream out = s.getOutputStream();
out.write("收到后反饋".getBytes());
s.close();
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
## 三.復制文件
> 同樣的這里也是使用的流,我們具體來看下怎么去操作,我們同樣的,寫在一個類中
~~~
package com.lgl.socket;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class FileClient {
public static void main(String[] args) {
try {
Socket s = new Socket("192.168.1.102", 10006);
BufferedReader bufr = new BufferedReader(new FileReader("test.txt"));
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufr.readLine()) != null) {
pw.println(line);
}
pw.print("over");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String str = bufIn.readLine();
System.out.println(str);
bufr.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class FileServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
PrintWriter out = new PrintWriter(new FileWriter("test1.txt"), true);
String line = null;
while ((line = bufIn.readLine()) != null) {
if ("over".equals(line))
break;
out.println(line);
}
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
pw.println("上傳成功");
out.close();
s.close();
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
## 四.上傳圖片
> 我們再來看下圖片是怎么上傳的,我們先來分析下步驟
### 客戶端
* 1.服務端點
* 2.讀取客戶端已有的圖片數據
* 3.通過socket,發送給服務端
* 4.讀取服務端反饋的信息
* 5.關閉資源
~~~
**
* 客戶端
*
* @author LGL
*
*/
public class PicClient {
public static void main(String[] args) {
try {
Socket s = new Socket("192.168.1.102", 10009);
FileInputStream fis = new FileInputStream("1.png");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
//告訴服務端數據寫完
s.shutdownInput();
InputStream in = s.getInputStream();
byte[] bufn = new byte[1024];
int num = in.read(bufn);
System.out.println(new String(bufn, 0, num));
fis.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
### 服務端
> 直接看代碼
~~~
/**
* 服務端
* @author LGL
*
*/
class PicServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10009);
Socket s = ss.accept();
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream("2.png");
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
out.write("上傳成功".getBytes());
fos.close();
s.close();
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
~~~
> 其實跟I/O區別真不大,但是概念一定要了解清楚
## 五.多并發上傳
> 多并發這個概念就是多人互動了,這對服務器的負荷還是有考究的,這里呢,我們就模擬一下,多人上傳圖片的場景,我們是怎么做的?我們還是在上傳圖片的那份代碼上更改
>
> 首先我們可以確定的是,這是服務端的代碼
* 這個服務端有個局限性,當A客戶端連接之后,被服務端獲取到,服務端就在執行代碼了,這個時候如果B客戶端連接只有等待,這就是我們需要多并發的原因了,為了讓多個客戶端同時連接,服務端最好就是講每個客戶端封裝到一個單獨的線程中,這樣就可以同時處理多個客戶端請求
> 如何定義線程?
* 只要明確了每個客戶端要在服務端執行的代碼即可
~~~
/**
* 服務端
*
* @author LGL
*
*/
class PicServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10009);
while (true) {
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 并發線程
* @author LGL
*
*/
class PicThread implements Runnable {
private Socket s;
public PicThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
String ip = s.getInetAddress().getHostAddress();
System.out.println("ip:" + ip);
long millis = System.currentTimeMillis();
File file = new File(millis + ".png");
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
out.write("上傳成功".getBytes());
fos.close();
s.close();
} catch (Exception e) {
throw new RuntimeException("上傳失敗");
}
}
}
~~~
> 其實我寫的代碼還是有點爛的,但是思想在就好,我們得先把思想學會了
## 六.多并發登錄
> 上面說的多并發的上傳,實在服務端端,現在我們來說下登錄,是作用在客戶端
~~~
package com.lgl.socket;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class LoginClient {
public static void main(String[] args) {
try {
Socket s = new Socket("192.168.1.102", 10008);
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
for (int i = 0; i < 3; i++) {
String line = bufr.readLine();
if (line == null) {
break;
}
out.println(line);
String info = bufIn.readLine();
System.out.println("info:" + info);
if (info.contains("歡迎")) {
break;
}
}
bufr.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 服務端
*
* @author LGL
*
*/
class LoginServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10008);
while (true) {
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 并發登陸
*
* @author LGL
*
*/
class UserThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
BufferedReader bufrIn = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String name = bufrIn.readLine();
// 模擬讀取數據庫的用戶名
BufferedReader bufr = new BufferedReader(new FileReader(
"user.txt"));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
boolean flag = false;
while ((line = bufr.readLine()) != null) {
if (line.equals(name)) {
flag = true;
break;
}
}
if (flag) {
System.out.println("已登錄");
out.print("歡迎");
} else {
System.out.println("重新登錄");
out.println("用戶名不存在");
}
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
~~~
> OK,這些代碼中可能會存在一些錯誤,因為代碼并沒有去實際的驗證中,我寫的時候也是跟著思想去走的,這樣寫代碼是極為友好的,這就是TCP的冰山一角了,不過關于這些,還有很多知識點,我們要做的就是把思想給掌握了,萬變不理其中
>
> 好的,最近寫文的時間,有點懈怠了,看來要發力了,嘻嘻,
## 有興趣的加群:555974449 一起來玩玩吧!
版權聲明:本文為博主原創文章,博客地址:http://blog.csdn.net/qq_26787115,未經博主允許不得轉載。
- 0-發現
- AndroidInterview-Q-A
- Android能讓你少走彎路的干貨整理
- LearningNotes
- temp
- temp11
- 部分地址
- 0-待辦任務
- 待補充列表
- 0-未分類
- AndroidView事件分發與滑動沖突處理
- Spannable
- 事件分發機制詳解
- 1-Java
- 1-Java-01基礎
- 未歸檔
- 你應該知道的JDK知識
- 集合框架
- 1-Java-04合集
- Java之旅0
- Java之旅
- JAVA之旅01
- JAVA之旅02
- JAVA之旅03
- JAVA之旅04
- JAVA之旅05
- JAVA之旅06
- JAVA之旅07
- JAVA之旅08
- JAVA之旅09
- java之旅1
- JAVA之旅10
- JAVA之旅11
- JAVA之旅12
- JAVA之旅13
- JAVA之旅14
- JAVA之旅15
- JAVA之旅16
- JAVA之旅17
- JAVA之旅18
- JAVA之旅19
- java之旅2
- JAVA之旅20
- JAVA之旅21
- JAVA之旅22
- JAVA之旅23
- JAVA之旅24
- JAVA之旅25
- JAVA之旅26
- JAVA之旅27
- JAVA之旅28
- JAVA之旅29
- java之旅3
- JAVA之旅30
- JAVA之旅31
- JAVA之旅32
- JAVA之旅33
- JAVA之旅34
- JAVA之旅35
- 1-Java-05辨析
- HashMapArrayMap
- Java8新特性
- Java8接口默認方法
- 圖解HashMap(1)
- 圖解HashMap(2)
- 2-Android
- 2-Android-1-基礎
- View繪制流程
- 事件分發
- AndroidView的事件分發機制和滑動沖突解決
- 自定義View基礎
- 1-安卓自定義View基礎-坐標系
- 2-安卓自定義View基礎-角度弧度
- 3-安卓自定義View基礎-顏色
- 自定義View進階
- 1-安卓自定義View進階-分類和流程
- 10-安卓自定義View進階-Matrix詳解
- 11-安卓自定義View進階-MatrixCamera
- 12-安卓自定義View進階-事件分發機制原理
- 13-安卓自定義View進階-事件分發機制詳解
- 14-安卓自定義View進階-MotionEvent詳解
- 15-安卓自定義View進階-特殊形狀控件事件處理方案
- 16-安卓自定義View進階-多點觸控詳解
- 17-安卓自定義View進階-手勢檢測GestureDetector
- 2-安卓自定義View進階-繪制基本圖形
- 3-安卓自定義View進階-畫布操作
- 4-安卓自定義View進階-圖片文字
- 5-安卓自定義View進階-Path基本操作
- 6-安卓自定義View進階-貝塞爾曲線
- 7-安卓自定義View進階-Path完結篇偽
- 8-安卓自定義View進階-Path玩出花樣PathMeasure
- 9-安卓自定義View進階-Matrix原理
- 通用類介紹
- Application
- 2-Android-2-使用
- 2-Android-02控件
- ViewGroup
- ConstraintLayout
- CoordinatorLayout
- 2-Android-03三方使用
- Dagger2
- Dagger2圖文完全教程
- Dagger2最清晰的使用教程
- Dagger2讓你愛不釋手-終結篇
- Dagger2讓你愛不釋手-重點概念講解、融合篇
- dagger2讓你愛不釋手:基礎依賴注入框架篇
- 閱讀筆記
- Glide
- Google推薦的圖片加載庫Glide:最新版使用指南(含新特性)
- rxjava
- 這可能是最好的RxJava2.x入門教程完結版
- 這可能是最好的RxJava2.x入門教程(一)
- 這可能是最好的RxJava2.x入門教程(三)
- 這可能是最好的RxJava2.x入門教程(二)
- 這可能是最好的RxJava2.x入門教程(五)
- 這可能是最好的RxJava2.x入門教程(四)
- 2-Android-3-優化
- 優化概況
- 各種優化
- Android端秒開優化
- apk大小優化
- 內存分析
- 混淆
- 2-Android-4-工具
- adb命令
- 一鍵分析Android的BugReport
- 版本控制
- git
- git章節簡述
- 2-Android-5-源碼
- HandlerThread 源碼分析
- IntentService的使用和源碼分析
- 2-Android-9-辨析
- LRU算法
- 什么是Bitmap
- 常見圖片壓縮方式
- 3-Kotlin
- Kotlin使用筆記1-草稿
- Kotlin使用筆記2
- kotlin特性草稿
- Kotlin草稿-Delegation
- Kotlin草稿-Field
- Kotlin草稿-object
- 4-JavaScript
- 5-Python
- 6-Other
- Git
- Gradle
- Android中ProGuard配置和總結
- gradle使用筆記
- Nexus私服搭建
- 編譯提速最佳實踐
- 7-設計模式與架構
- 組件化
- 組件化探索(OKR)
- 1-參考列表
- 2-1-組件化概述
- 2-2-gradle配置
- 2-3-代碼編寫
- 2-4-常見問題
- 2-9-值得一讀
- 8-數據結構與算法
- 0臨時文件
- 漢諾塔
- 8-數據-1數據結構
- HashMap
- HashMap、Hashtable、HashSet 和 ConcurrentHashMap 的比較
- 遲到一年HashMap解讀
- 8-數據-2算法
- 1個就夠了
- Java常用排序算法(必須掌握的8大排序算法)
- 常用排序算法總結(性能+代碼)
- 必須知道的八大種排序算法(java實現)
- 9-職業
- 閱讀
- 書單
- 面試
- 面試-01-java
- Java面試題全集駱昊(上)
- Java面試題全集駱昊(下)
- Java面試題全集駱昊(中)
- 面試-02-android
- 40道Android面試題
- 面試-03-開源源碼
- Android圖片加載框架最全解析(二),從源碼的角度理解Glide的執行流程
- 面試-07-設計模式
- 面試-08-算法
- 面試-09-其他
- SUMMARY
- 版權說明
- temp111