热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android网络编程TCP/IP协议实践

前言简要回顾了TCPIP分层模型及IP、TCP、UDP等主要协议,并且在此基础上联系Android,做出一定的代码实现。推荐书目:《深入理解Android网络编程》、《计算机网络–

前言

  • 简要回顾了 TCP/IP 分层模型及 IP、TCP、UDP 等主要协议,并且在此基础上联系 Android,做出一定的代码实现。
  • 推荐书目:《深入理解Android网络编程》、《计算机网络 – 自顶向下方法》、《TCP/IP详解》

网络协议概述

  • 大多数网络都采用分层的体系结构,每一层都建立在它下层之上,同时向它的上一层提供服务。
  • 网络各层中存在许多协议,接收方与发送方同层协议必须一致。
  • 由于网络结点之间联系复杂,制定协议,通常把复杂成分分解成简单的成分,再将它们组合。
    常用的复合技术 – “层级结构”:
    • 结构中每一层都规定明确的任务以及接口标准
    • 将用户的应用程序作为最高层
    • 除了最高层,中间的每一层都向上提供服务,同时又是下一层的用户
    • 物理层座位最低层,使用最高层传来的参数,是提供服务的基础
  • ISO提出的OSI/RM模型将计算机网络体系结构通讯协议划分为七层:物理层、数据链路层、网络层、传输层、;会话层、表示层、应用层(物数网传会表应)
    低4层完成数据传输服务、高3层面向用户:
  • 应用层 – 为应用提供访问网络服务接口
  • 表示层 – 提供数据/信息表示变换,让不同编码计算机可相互理解
  • 会话层 – 组织同步不同计算机的进程通信(对话),对话的建立与拆除;还提供在数据流中插入同步点机制,数据传输中断后,也不必从头开始,仅重传最近一个同步点以后的数据
  • 传输层 – 源主机与目的主机的连接与数据传输(端到端的数据传输)
  • 网络层 – 寻找合适的路由,使网络层数据传输单元(分组)可以正确找到目的站
  • 数据链路层 – 两个相邻结点间无差错地以帧为单位的数据传送
  • 物理层 – 物理介质传输,比特流传输

IP、TCP 和 UDP 协议

IP 协议

  • 即互联网协议(Internet Protocol),用于报文交换网络的一种面向数据的协议,是TCP/IP协议中网络层的主要协议。
  • 作用:根据源主机和目的主机的地址传送数据。
  • IP定义了寻址方法和数据报的封装结构。(IPv4、IPv6)

TCP 协议

  • TCP/IP模型中,面向连接的、可靠的、基于字节流的传输层通信协议;
  • 传输层存在的意义:应用层之间需要可靠的,像管道一样的连接,但网络层不提供这样的流机制,只提供不可靠的包交换,因此需要传输层的协调。
  • TCP协议作用:
    • TCP协议把应用层向传输层发送网间传输的、用8位字节表示的数据流分成适当长度的报文段(受数据链路层最大传输单元MTU限制);
    • 把包传给网络层,由网络层将包传送给接收端实体的传输层;TCP为了不发生丢包,给每个包一个序号,同时序号保证了传送到接收端实体的包能按序接收。然后接收实体成功收到包后回复相应的ACK确认;
    • 如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就会被认为丢失,将被重传;
    • TCP协议用一个校验和(Checksum)函数来检验数据是否错误,发送与接收时候都需要计算校验和。

UDP 协议

  • TCP/IP模型中面向无连接的传输层协议,提供面向事务的简单不可靠信息传输服务。
  • UDP不提供对IP协议的可靠机制、流控制以及错误恢复功能等,在数据传输之前不需要简历连接。
  • 由于UDP较简单,因此比TCP负载消耗少。

Android 中的运用?

TCP、UDP报文结构中,每段报文除了数据本身,还包含了许多其他重要信息,而且长度有限,传输时候需要拆解,到达目的地之后再组合还原,如果包有丢失或者损坏还需要重传,乱序发送的包还需要重新排序。
处理传输过程中的一系列逻辑,需要大量可靠的代码完成。于是人们他用过 Socket 对网络纠错、包大小、包重传等进行封装。

Socket 基础

  • 从字面意思来看,“Socket”通常被称为“套接字”。相信很多人都不理解“套接字”是什么意思,包括我,也是疑惑了很久。
  • Socket 作用距离:一台服务器可能会提供多种服务,每种服务对应一个 Socket,客户也持有一个 Socket,客户需要哪种服务,就需要找到对应的Socket来进行通信。
  • Socket 是应用层与TCP/IP协议族通信的中间软件抽象层,它本质是一组接口。Socket 接口将复杂的TCP/IP协议族隐藏,对用户而言,一组简单的接口就是全部,让 Socket 组织数据,以符合指定协议。
  • 应用程序常通过 Socket 向网络发送/响应请求
  • Socket 基本操作:1、连接远程机器;2、发送数据;3、接收数据;4、关闭连接;5、绑定端口;6、监听到达数据;7、在绑定端口上接收来自远程及其的连接
  • 服务器要和客户端通信,两者需要实例化一个Socket。服务器和客户端的Socket不一样,客户端可以实现连接远程机器、发送数据、接收数据、关闭连接等,服务器还需要实现绑定端口、监听到达数据、接收来自远程机器的连接。Android 中,java.net里面提供的两个类:ServerSocket、Socket,前者用于实例化服务器 Socket,后者用于实例化客户端的 Socket。
  • Socket 的两种类型:TCP、UDP
    TCP 与 UDP 在传输过程中的具体实现方式不同,两者都接收传输协议数据包并将其内容向前传递到应用层。
    TCP 把消息分解成数据包,并在接收端以正确的顺序将他们重新装配起来;TCP 还处理丢包的重传请求,位于上层的应用层要处理的事情就相对较少。
    UDP 不提供装配与处理重传请求,只是向前传递信息包,位于上层的应用必须确保消息是完整的,并且是以正确的顺序装配的。

使用 TCP 通信与 UDP 通信

  • TCP:保证可靠性上,采用超时重传和捎带确认机制;流量控制上,采用滑动窗口协议(协议规定,对于窗口内,未经确认的分组需要重传);拥塞机制上,采用慢启动算法。
    场景应用:当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。

    • TCP 服务器端工作流程:

      1. SerserSocket(int port) 创建 ServerSocket,并将其绑定到指定端口
      2. 调用 accept(),监听连接请求,如果客户端请求连接,则接受并返回通信 Socket
      3. 调用 Socket 类的 getOutputStream()、getInputStream() 获取输出和输出流,开始网络数据发送与接收
      4. 通信结束,关闭通信套接字
    • TCP 客户端工作流程:

      1. 调用 Socket() 创建一个流套接字,并且连接至服务器端
      2. 调用 Socket 类中的 getOutputStream()、getInputStream() 方法获取输出和输入流,开始网络数据的发送与接收
      3. 通信结束,关闭通信套接字
  • UDP:有不提供数据报分组、组装和不能对数据包排序的缺点,无法得知其是否安全完整到达。UDP 主要用来支持那些需要在计算机之间传输数据的网络应用,对网络通讯质量要求不高,要求较快的通信速度时使用。
    主要作用:将网络数据流量压缩成数据报的形式。(典型数据报:一个二进制的传输单位)

    • UDP 服务器端工作流程:

      1. 调用 DatagramSocket(int port) 创建一个数据报套接字,并绑定到指定端口
      2. 调用 DatagramPacket(byte[]buf,int length),建立字节数组以接收 UDP 包
      3. 调用 DatagramSocket 类的receiver(),接受 UDP 包
      4. 通信结束,关闭数据报套接字
    • UDP 客户端工作流程:

      1. 调用 DatagramSocket() 创建一个数据报套接字
      2. 调用 DatagramPacket(byte[]buf,int offset,int length,InetAddress address,int port),建立要发送的 UDP 包
      3. 调用 DatagramSocket 类的 send() 发送 UDP 包
      4. 通信结束,关闭数据报套接字

简单的通信 Demo

实现了服务器端与客户端的交互(客户端发送消息至服务器端);

ChatServer.java
public class ChatServer extends Thread {
/**
* 服务器Socket对象
*/
private ServerSocket server = null;
/**
* 端口
*/
public static final int PORT = 5000;
/**
* 读写Buffer
*/
private BufferedReader reader;
private BufferedWriter writer;
/**
* 主线程Handler
*/
private final Handler handler;
/**
* 标识
*/
public static final int SERVER_TAG = 12345;
public static final String MSG_KEY = "server";
public ChatServer(Handler handler) throws IOException {
this.handler = handler;
createSocket();
}
/**
* 创建ServerSocket
*/
private void createSocket() throws IOException {
server = new ServerSocket(PORT, 100);
}
@Override
public void run() {
Socket client;
String text;
try {
//死循环监听
while (true) {
//响应客户端连接请求
client = responseSocket();
while (true) {
//接收客户端发送的消息
text = receiveMsg(client);
//显示消息结果
makeTips(text);
break;
}
closeSocket(client);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 关闭连接及缓存
*
* @param client
*/
private void closeSocket(Socket client) throws IOException {
reader.close();
// writer.close();
client.close();
}
/**
* 发送消息到客户端
*
* @param client
* @param text
*/
private void sendMsg(Socket client, String text) throws IOException {
writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
writer.write(text + "\n");
writer.flush();//发送
}
/**
* 提示
*
* @param text
*/
private void makeTips(String text) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString(ChatServer.MSG_KEY, text);
msg.setData(bundle);
msg.what = SERVER_TAG;
handler.sendMessage(msg);
}
private String receiveMsg(Socket client) throws IOException {
reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String result = reader.readLine();
return "服务器收到:" + result;
}
private Socket responseSocket() throws IOException {
return server.accept();
}
}

ChatClient.java
public class ChatClient {
private Socket socket = null;
public ChatClient(String host, int port) throws IOException {
socket = new Socket(host, port);
}
/**
* 向服务器端发送消息
*
* @param msg
* @throws IOException
*/
public void sendMsg(String msg) throws IOException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write(msg.replace("\n", "") + "\n");
writer.flush();
}
}

MainActivity.java
public class MainActivity extends AppCompatActivity {
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ChatServer.SERVER_TAG:
Bundle bundle = msg.getData();
Toast.makeText(MainActivity.this, bundle.getString(ChatServer.MSG_KEY), Toast.LENGTH_LONG).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_main);
launchServer();
launchClient();
}
private void launchServer() {
//启动服务器端
try {
ChatServer
chatServer = new ChatServer(handler);
chatServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 启动客户端
*/
private void launchClient() {
new Thread(new Runnable() {
@Override
public void run() {
ChatClient client = null;
try {
client = new ChatClient(null, ChatServer.PORT);
client.sendMsg("客户端给服务器端,发了一条信息");
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}

推荐阅读
  • Linux防火墙配置—允许转发
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 本文分享了一位Android开发者多年来对于Android开发所需掌握的技能的笔记,包括架构师基础、高级UI开源框架、Android Framework开发、性能优化、音视频精编源码解析、Flutter学习进阶、微信小程序开发以及百大框架源码解读等方面的知识。文章强调了技术栈和布局的重要性,鼓励开发者做好学习规划和技术布局,以提升自己的竞争力和市场价值。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 介绍一款好用的内网穿透工具FRP
    本文介绍了一款好用的内网穿透工具FRP,它是一个使用Go语言开发的高性能的反向代理应用。FRP支持多种协议类型,并且可以根据域名进行路由转发。 ... [详细]
  • 概述H.323是由ITU制定的通信控制协议,用于在分组交换网中提供多媒体业务。呼叫控制是其中的重要组成部分,它可用来建立点到点的媒体会话和多点间媒体会议 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
author-avatar
v05736708
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有