# 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