Android Socket

参考资料

菜鸟教程

怎么理解TCP的面向连接和UDP的无连接

https://www.cnblogs.com/xiaomayizoe/p/5258754.html

https://www.cnblogs.com/qifengshi/p/6602881.html

Overview

Socket 一词起源于UNIX 操作系统,UNIX 系统中将IP + 端口号 的通信的方式称之为Socket 中文译为套接字 ,在学习Socket的时候不要太过于纠结它的名字,毕竟只是个代号。

TCP和UDP

首先要想比较容易的理解TCP和UDP协议,首先得对整体的网络协议框架有一个整体的了解,并不需要多清楚,只要把握整体就好了,这里我推荐 阮一峰 阮老师的博客 网络协议入门1 , 网络协议入门2

这里的TCP 协议不等于TCP/IP协议族 ,这一点不要弄混。

首先呢UDP 是先与TCP 出现的,但是UDP协议是存在着一些“问题”的,所有后来就有了更为复杂的TCP协议。

UDP(User Datagram Protocol)协议

如果已经知道对方的IP端口号 ,通过UDP协议我们是已经可以实现,不同的计算机的程序之间的通信了,但是UDP协议还存在着一个“问题”。

  • UDP协议是一种无连接的协议(发送数据之前无需建立连接),不能确保服务器是否收到了发送的数据,这就不能保证数据的完成性,当服务器高负载的情况下很容易出现。
  • UDP协议无法保证发送数据的顺序

比如说,通过UDP协议向服务器发送了如下的数据

11

22

33

但是服务器可能接收到的是

33

11

22

但是这种,情况一般是在网络拥堵的情况下才会出现。

TCP(Transmission Control Protocol) 协议

因为UDP的一些“弊端”,所以TCP协议出现了,TCP协议,面向连接,发送数据有顺序,不会造成丢包,但是一些代价也随之而来。TCP与UDP相比消耗的资源较多。

TCP 三次握手

https://www.cnblogs.com/qifengshi/p/6602881.html

总结

当对数据的完整性非常高的的时候,需要采用TCP协议传输,比如传输文件 ,发送邮件

当对数据完成行要求不高的时候,可以采用UDP协议,比如视频通话

UDP 和 TCP 没有绝对的好与坏,之后谁更适用。

InetAddress

This class represents an Internet Protocol (IP) address.

该类代表着一个IP地址.

  1. /**
  2. * 获取本机信息
  3. * 主机名
  4. * IP地址
  5. */
  6. private void getLocalHostInfo() {
  7. try {
  8. InetAddress inetAddress = InetAddress.getLocalHost();
  9. String hostName = inetAddress.getHostName();
  10. String ipAddress = inetAddress.getHostAddress();
  11. System.out.printf("HostName:%s IP Address:%s", hostName, ipAddress);
  12. } catch (UnknownHostException e) {
  13. e.printStackTrace();
  14. }
  15. }

基于TCP的Socket

一个DEMO

通过Socket实现文件上传到服务器的功能,上传功能具有断点续传机制。

效果图如下

实现思路如下

首先,需要在Android 的 Assets 目录下,放入一个名为tmep.flv 的视频文件,

客户端实现思路
  1. 建立与服务端的连接
  2. 选择要上传的文件
  3. 在写入文件的时候,要先想服务器发送头信息(如: 要上传的文件的名称)
  4. 当暂停的时候释放Socket占用的资源,并且记录已经写入了的长度
  5. 当再次开始的时候,获取已经写入了的长度,在写入的时候通过流的skip 方法,跳过这些流。
  6. 建立新的Socket连接,继续向服务器发送数据

PS: 在写入的时候会更新进度条,来显示写入进度

服务端实现思路
  1. 开启服务等待客户端了连接
  2. 当客户端连接后,首先获取客户端传递过来的头信息
  3. 获取到头信息的文件名后,在本地建立文件并写入
  4. 当客户端暂停后,清空资源,等待客户端再次连接
  5. 当客户端再次连接后,向本地已经存在的文件中追加数据
注意事项
  • 在没有完全地交互完的时候,不要关闭流,如果关闭了流,那么Socket连接也会关闭,会抛出SocketClosed 异常。

代码实现

服务端代码

  1. /**
  2. * 通过Socket来实现上传操作
  3. */
  4. public class SocketUploadClass implements ICallAble {
  5. private ServerSocket serverSocket;
  6. //线程池
  7. ExecutorService executorService;
  8. @Override
  9. public void call() {
  10. try {
  11. startServer();
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. /**
  17. * 初始化服务器
  18. */
  19. private void startServer() throws IOException {
  20. serverSocket = new ServerSocket(9988);
  21. //创建线程池 线程数 = 可用cpu 数量 * 50
  22. this.executorService =
  23. Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);
  24. //等待客户端接入
  25. while (true) {
  26. Socket socket = serverSocket.accept();
  27. executorService.execute(new SocketTask(socket));
  28. }
  29. }
  30. /**
  31. * 用来处理用户写入的县城类
  32. */
  33. class SocketTask implements Runnable {
  34. //连接到服务器的线程
  35. Socket socket;
  36. public SocketTask(Socket socket) {
  37. this.socket = socket;
  38. }
  39. @Override
  40. public void run() {
  41. String ipAddress = socket.getInetAddress().toString();
  42. int port = socket.getPort();
  43. System.out.printf("Client 【%s】 Port:%d 已连接", ipAddress, port);
  44. //接收数据
  45. try {
  46. InputStream inputStream = socket.getInputStream();
  47. BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
  48. //读取第一行的头信息
  49. String header = "";
  50. int i;
  51. while ((i = inputStream.read()) != -1) {
  52. if (i == '\r')
  53. break;
  54. header += (char) i;
  55. }
  56. System.out.println(header);
  57. //要存储的文件名
  58. String fileName = header.split("=")[1];
  59. //将传递过来的内容写入到本地文件
  60. byte[] buffer = new byte[1024];
  61. FileOutputStream fileOutputStream = new FileOutputStream(fileName, true);
  62. BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
  63. int len;
  64. while ((len = bufferedInputStream.read(buffer)) != -1) {
  65. bufferedOutputStream.write(buffer, 0, len);
  66. }
  67. //释放资源
  68. bufferedOutputStream.flush();
  69. bufferedInputStream.close();
  70. bufferedOutputStream.close();
  71. } catch (IOException e) {
  72. e.printStackTrace();
  73. }
  74. }
  75. }
  76. }

客户端代码

布局文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <Button
  7. android:id="@+id/uploadBtn"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:onClick="upload"
  11. android:text="Update"/>
  12. <Button
  13. android:id="@+id/pauseBtn"
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content"
  16. android:onClick="pause"
  17. android:text="Pause"/>
  18. <ProgressBar
  19. android:id="@+id/processPB"
  20. style="@style/Widget.AppCompat.ProgressBar.Horizontal"
  21. android:layout_width="match_parent"
  22. android:layout_height="wrap_content"/>
  23. </LinearLayout>

Activity代码

  1. public class SocketUploadActivity extends CommonActivity {
  2. private ProgressBar mProgressBar;
  3. private Button mPauseBtn;
  4. private Button mUploadBtn;
  5. private Socket mSocket;
  6. //要上传的文件名称
  7. private String fileName = "temp.flv";
  8. //标识是否开始写入
  9. private boolean start = true;
  10. private int mCurrentLen;
  11. @Override
  12. public int layoutId() {
  13. return R.layout.activity_socket_upload;
  14. }
  15. @Override
  16. public void init() {
  17. mUploadBtn = (Button) this.findViewById(R.id.uploadBtn);
  18. mPauseBtn = (Button) this.findViewById(R.id.pauseBtn);
  19. mProgressBar = (ProgressBar) this.findViewById(R.id.processPB);
  20. }
  21. /**
  22. * 上传文件
  23. */
  24. public void upload(View view) {
  25. AssetManager manager = this.getAssets();
  26. new Thread(() -> {
  27. try {
  28. start = true;
  29. if (mSocket == null || mSocket.isClosed())
  30. mSocket = new Socket("10.0.2.2", 9988);
  31. InputStream inputStream = manager.open(fileName);
  32. //当前已经读取到的总长度
  33. mCurrentLen = getSharedPreferences("socketConfig", MODE_PRIVATE).getInt(fileName, 0);
  34. int totalLen = inputStream.available(); //总长度
  35. int currentRate = 0;
  36. byte[] buffer = new byte[1024];
  37. int len;
  38. //读取文件
  39. OutputStream outputStream = mSocket.getOutputStream();
  40. BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
  41. //跳过已经传输了的宽度
  42. inputStream.skip(mCurrentLen);
  43. //写入一行头信息,告知服务器一些关于文件的信息,这里仅仅写入了文件的名称,也可以写入其他的
  44. bufferedOutputStream.write(("file=" + fileName + "\r").getBytes("UTF-8"));
  45. //当用户没有暂停上传,并且还有数据的时候,写入数据
  46. while (start && (len = inputStream.read(buffer)) != -1) {
  47. bufferedOutputStream.write(buffer, 0, len);
  48. //计算已经写入了的长度
  49. mCurrentLen += len;
  50. //计算已经上传了的比例
  51. int rate = (int) Math.floor(mCurrentLen * 1.0 / totalLen * 100);
  52. //更新进度,更新进度条不需要返回UI线程,直接更新就行
  53. if (rate > currentRate) {
  54. currentRate = rate;
  55. mProgressBar.setProgress(rate);
  56. L.e("Total Len=: " + totalLen + " Rate:" + rate);
  57. }
  58. }
  59. //释放资源
  60. bufferedOutputStream.flush();
  61. inputStream.close();
  62. bufferedOutputStream.close();
  63. outputStream.close();
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. }
  67. }).start();
  68. }
  69. /**
  70. * 暂停写入,关闭Socket连接,将已经写入的长度进行存储,实现断点续传
  71. */
  72. public void pause(View view) throws IOException {
  73. start = false;
  74. //为了进行断点续传,将已经写入的数据的长度存储起来
  75. SharedPreferences.Editor editor =
  76. this.getSharedPreferences("socketConfig", MODE_PRIVATE).edit();
  77. editor.putInt(fileName, mCurrentLen);
  78. editor.apply();
  79. mSocket.close();
  80. }
  81. }

检验是否上传成功

看一看我们长传过来的视频是否能够正常播放,如果能够就证明我们上传成功了。

Android Socket的更多相关文章

  1. Android Socket编程学习笔记

    http://blog.csdn.net/eyu8874521/article/details/8847173 度娘给出的描述:通常也称作"套接字",用于描述IP地址和端口,是一个 ...

  2. Protobuf实现Android Socket通讯开发教程

    本节为您介绍Protobuf实现Android Socket通讯开发教程,因此,我们需要先了理一下protobuf 是什么? Protocol buffers是一种编码方法构造的一种有效而可扩展的格式 ...

  3. Android Socket通信详解

    一.Socket通信简介  Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客 ...

  4. Android Socket编程

    花了大概两天的时间,终于把Android的Socket编程给整明白了.抽空和大家分享一下: Socket Programming on Android Socket 编程基础知识: 主要分服务器端编程 ...

  5. Android Socket 通信

    Android socket 通信 安卓编写Socket客户端,实现连接Socket服务端通信. 创建Socket连接并获取服务端数据 先创建几个全局变量吧 private BufferedWrite ...

  6. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  7. android socket 线程连接openwrt与arduino单片机串口双向通信

    package zcd.netanything; import java.io.BufferedReader; import java.io.InputStreamReader; import jav ...

  8. android socket编程用Bufferreader读取的一个失败教训

    由于我的手机需要用笔记本开的wifi,躺在床上玩手机时需要关电脑或者是要让电脑放歌的时候总是不想下床,于是我想能不能用一个APP,然后通过局域网实现在手机上对电脑进行操控呢?说干就干. 我在电脑上用的 ...

  9. 一个Android Socket的例子

    1.开篇简介 Socket本质上就是Java封装了传输层上的TCP协议(注:UDP用的是DatagramSocket类).要实现Socket的传输,需要构建客户端和服务器端.另外,传输的数据可以是字符 ...

随机推荐

  1. eos交易同步过程和区块生产过程源码分析

    交易同步过程 1 通过命令cleos调用 cleos transfer ${from_account} ${to_account} ${quantity} 发起交易2 eos调用chain_plugi ...

  2. css3 :nth-child()选择器的使用

    一.nth-child() 1. nth-child(n):父元素下的第n个子元素,n>0,索引从1开始.不区分子元素类型. 2. nth-child(odd):父元素下的奇数子元素,等同于:n ...

  3. Spark记录-Scala shell命令

    1.scala shell命令 scala> :help All commands can be abbreviated, e.g., :he instead of :help. :edit & ...

  4. HDU 5528 反演

    $f(m)=\sum\limits_{i=1}^{m-1}\sum\limits_{j=1}^{m-1}[(ij,m) \ne m]$,$g(n)=\sum\limits_{m|n}f(m)$,$1 ...

  5. 【官方文档】Nginx模块Nginx-Rtmp-Module学习笔记(一) RTMP 命令详解

    源码地址:https://github.com/Tinywan/PHP_Experience 说明: rtmp的延迟主要取决于播放器设置,但流式传输软件,流的比特率和网络速度(以及响应时间“ping” ...

  6. Brief History of Machine Learning

    Brief History of Machine Learning My subjective ML timeline Since the initial standpoint of science, ...

  7. zabbix user parameters和Loadable modules的使用方法介绍

    目录 需求 实现 原理 前端配置 后端配置 shell实现 python实现 C实现 需求: 采集主机的-/+ buffers/cache  free的数据 实现: 采集/proc/meminfo中的 ...

  8. Thinkpad X220 升级 Windows 10 后无线网卡消失问题

    11年购买的Thinkpad X220从Win7升级到Win10后,用着还是挺顺手的,网络显示等一切正常,直到今天合上盖子电脑睡眠以后再次打开,wifi消失不见.重启,关机再开机,都没用,只显示有线网 ...

  9. (FFT)A+B Problem

    题目链接:https://cn.vjudge.net/contest/280041#problem/B 题目大意:给你n个数,然后让你找满足a[i] + a[j] = a[k] 的情况总数. 具体思路 ...

  10. CodeForces Contest #1110: Global Round 1

    比赛传送门:CF #1110. 比赛记录:点我. 涨了挺多分,希望下次还能涨. [A]Parity 题意简述: 问 \(k\) 位 \(b\) 进制数 \(\overline{a_1a_2\cdots ...