Android网络 | Socket(Eclipse--Java)

本文涉及的产品
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
简介: Android网络 | Socket(Eclipse--Java)
  • **在现实网络传输应用中,

通常使用TCPIPUDP这3种协议实现数据传输

传输数据的过程中,
需要通过一个双向的通信连接实现数据的交互

在这个传输过程中,
通常将这个双向链路的一端称为Socket
一个Socket通常由一个IP地址和一个端口号来确定。

在整个数据传输过程中Socket的作用是巨大的。
在Java编程应用中,Socket是Java网络编程的核心。**

Socket基础

  • **在网络编程中有两个主要的问题

一个是如何准确地定位网络上一台或多台主机,
另一个就是找到主机后如何可靠高效地进行数据传输

TCP/IP协议
IP层主要负责网络主机的定位数据传输路由
IP地址可以唯一地确定Internet上的一台主机
TCP层
提供面向应用的可靠(TCP)
非可靠(UDP)数据传输机制
这是网络编程主要对象
一般不需要关心IP 层如何处理数据的。

目前较为流行的网络编程模型客户机/服务器(C/S)结构
通信双方,一方作为服务器
等待(另一方作为的)客户提出请求并予以响应
客户则在需要服务时向服务器提出申请

服务器一般作为守护进程 始终运行,
监听网络端口,
一旦有客户请求,就会启动一个服务进程来响应该客户,
同时自己继续监听服务端口
使后来的客户也能及时得到服务。**

TCP/IP协议基础

  • **TCP/IPTransmission Control Protocol/Internet Protocol的简写,

中译名为传输控制协议/因特网协议
又名网络通信协议
是Internet最基本的协议Internet国际互联网络基础

网络层IP协议
传输层TCP协议组成。

TCP/IP定义了电子设备如何连入因特网
以及数据如何在它们之间传输的标准

TCP/IP协议采用了4层层级结构
每一层都呼叫它的下一层所提供的协议来完成自己的需求

也就是说,
TCP负责发现传输的问题,
一旦发现问题便发出信号要求重新传输
直到所有数据安全正确地传输到目的地
IP的功能是给因特网的每一台电脑规定一个地址

TCP/IP协议不是TCPIP这两个协议的合称
而是指因特网整个TCP/IP协议簇

协议分层模型方面来讲,TCP/IP4个层次组成,
分别是网络接口层网络层传输层应用层
**

  • **其实TCP/IP协议并不完全符合OSI(Open System Interconnect)7层参考模型

OSI是传统的开放式系统互连参考模型
是一种通信协议7层抽象参考模型
其中每一层执行某一特定任务
该模型的目的
使各种硬件相同的层次相互通信

7层
物理层、数据链路层(网络接口层)
网络层(网络层)
传送层(传输层)
会话层、表示层和应用层(应用层)
TCP/IP协议采用了4层的层级结构,
每一层都呼叫它的下一层所提供的网络来完成自己的需求

由于ARPANET的设计者注重的是网络互联
允许通信子网(网络接口层)采用已有的或是将来有的各种协议
所以这个层次中没有提供专门的协议

实际上,
TCP/IP协议可以通过网络接口层连接到任何网络上,
例如X.25交换网IEEE802局域网。**

UDP协议

  • **UDPUser Datagram Protocol的简称,

是一种无连接的协议,
每个数据报都是一个独立的信息
包括完整源地址目的地址
它在网络上以任何可能的路径传往目的地
因此能否到达目的地
到达目的地的时间以及内容的正确性都是不能被保证的。

现实网络数据传输过程中
大多数功能是由TCP协议UDP协议实现。**

  • **(1)TCP协议

面向连接的协议,
Socket之间进行数据传输之前必然要建立连接
所以在TCP中需要连接时间

TCP传输数据大小限制
一旦连接建立起来,
双方的Socket就可以按统一的格式传输大的数据
TCP是一个可靠的协议
它确保接收方完全正确地获取发送方所发送的全部数据。**

  • **(2)UDP协议

每个数据报中都给出了完整地址信息
因此无需要建立发送方接收方连接

UDP传输数据时是有大小限制的,
每个被传输的数据报必须限定在64KB之内。

UDP是一个不可靠的协议,
发送方所发送的数据报并不一定以相同的次序到达接收方。**

TCP、UDP选择的决定因素
  • **(1)TCP在网络通信上有极强生命力

例如远程连接(Telnet)文件传输(FTP)
都需要不定长度数据可靠地传输
但是可靠的传输是要付出代价的,
数据内容正确性的检验必然占用计算机的处理时间网络的带宽
因此TCP传输效率不如UDP高。**

  • **(2)UDP 操作简单,而且仅需要较少的监护

因此通常用于局域网高可靠性分散系统Client/Server 应用程序
例如视频会议系统
并不要求音频视频数据 绝对的正确
只要保证连贯性就可以了,
这种情况下显然使用UDP更合理一些,
因为TCPUDP都能达到这个保证连贯性的门槛,
但是TCP却要多占用更多的计算机资源
杀鸡焉用牛刀呢,
所有这种情况不用TCP,用UDP。**

基于Socket的Java网络编程

  • **网络上的两个程序通过一个双向通信连接实现数据的交换

这个双向链路一端称为一个Socket。**

  • Socket通常用来实现客户方服务方的连接。
  • **SocketTCP/IP协议的一个十分流行的编程方式,

一个Socket一个IP地址一个端口号 唯一确定
但是,
Socket所支持的协议种类也不光TCP/IP一种,
因此两者之间是没有必然联系的。
Java环境下,
Socket编程主要是指基于TCP/IP协议网络编程。**

1.Socket通信的过程
  • **ServerListen(监听)某个端口是否有连接请求

Client端Server 端发出Connect(连接)请求
Server端Client端发回Accept(接收)消息
一个连接就建立起来了。**

  • Server端Client端都可以通过SendWrite等方法与对方通信
  • **在Java网络编程应用中,

对于一个功能齐全的Socket来说,
其工作过程包含如下所示的基本步骤。
(1)创建ServerSocketSocket
(2)打开连接到Socket输入/输出流
(3)按照一定的协议对Socket进行读/写操作
(4)关闭IO流Socket。**

2.创建Socket
  • **在Java网络编程应用中,

java.net中提供了两个类SocketServerSocket
分别用来表示双向连接客户端服务端
这是两个封装得非常好的类,
其中包含了如下所示的构造方法:**

  • Socket(InetAddress address, int port);
  • Socket(InetAddress address, int port, boolean stream);
  • Socket(String host, int prot);
  • Socket(String host, int prot, boolean stream);
  • Socket(SocketImpl impl);
  • Socket(String host, int port, InetAddress localAddr, int localPort);
  • Socket(InetAddress address, int port, InetAddress localAddr, int localPort);
  • ServerSocket(int port);
  • ServerSocket(int port, int backlog);
  • ServerSocket(int port, int backlog, InetAddress bindAddr)
  • **在上述构造方法中,

参数addresshostport分别是
双向连接另一方IP地址主机名端口号
stream指明Socket流Socket还是数据报Socket
localPort表示本地主机端口号
localAddrbindAddr本地机器的地址ServerSocket主机地址),
implSocket父类
既可以用来创建ServerSocket又可以用来创建Socket。**
例如:

    Socket client = new Socket("127.0.0.1", 80);
    ServerSocket server = new ServerSocket(80);
  • **注意:

必须小心地选择端口
每一个端口提供一种特定的服务
只有给出正确的端口,才能获得相应的服务

0~1023 端口号系统所保留
例如
HTTP 服务的端口号为80,
Telnet服务的端口号为21,
FTP服务的端口号为23
所以我们在选择端口号时,最好选择一个大于1023以防止发生冲突
另外,
创建Socket时如果发生错误,将产生 IOException
程序中必须对之做出处理
所以在创建 Socket ServerSocket时必须捕获抛出异常。**

TCP编程详解

  • **TCP/IP通信协议是一种可靠网络协议

能够在通信的两端各建立一个Socket
从而在通信的两端之间形成网络虚拟链路

一旦建立了虚拟的网络链路
两端的程序就可以通过虚拟链路进行通信

Java语言对TCP网络通信提供了良好的封装
通过Socket对象代表两端通信端口
并通过Socket产生的IO流进行网络通信

这里先笔记Java应用中TCP编程的基本知识,
为后面的Android编程打下基础。**

使用ServerSocket

在Java程序中,

  • **使用

类ServerSocket 接受其他通信实体连接请求
对象ServerSocket的功能是监听来自客户端的Socket连接
如果没有连接则会一直处于等待状态。**

  • **在类ServerSocket中包含了如下监听客户端连接请求的方法:

Socket accept():如果接收到一个客户端Socket连接请求
该方法将返回一个与客户端Socket对应的Socket
否则该方法将一直处于等待状态,线程也被阻塞。**

  • **为了创建ServerSocket对象

ServerSocket类为我们提供了如下构造器:**

- **`ServerSocket(int port)`:

用指定的端口port创建一个ServerSocket
端口应该是有一个有效端口整数值0~65535。**

- **`ServerSocket(int port,int backlog)`:

增加一个用来改变连接队列长度参数backlog。**

- **`ServerSocket(int port,int backlog,InetAddress localAddr)`:

机器(服务器、本机等)存在多个IP地址的情况下,
允许通过localAddr这个参数
来指定将ServerSocket绑定到指定的IP地址。**

  • **当使用ServerSocket后,

需要使用ServerSocket中的方法close()关闭该ServerSocket。**

  • **在通常情况下,

因为服务器不会只接受一个客户端请求
而是会不断地接受来自客户端所有请求
所以可以通过循环不断调用ServerSocket中的方法accept()。**

  • 例如下面的代码。
    //创建一个ServerSocket,用于监听客户端Socket的连接请求
    ServerSocket ss = new ServerSocket(30000);
    //采用循环不断接受来自客户端的请求
    while (true)
    {
    //每当接受到客户端Socket的请求,服务器端也对应产生一个Socket
    Socket s = ss.accept();
    //下面就可以使用Socket进行通信了
    ...
    }
  • **在上述代码中,

创建的ServerSocket没有指定IP地址
ServerSocket绑定本机默认IP地址

在代码中使用30000作为该ServerSocket端口号
通常推荐使用10000以上的端口
主要是为了避免与其他应用程序通用端口 冲突。**

使用Socket
  • **在客户端可以使用Socket构造器

实现`和指定服务器连接`,
Socket中可以使用如下两个构造器:**

- **`Socket(InetAddress/String remoteAddress, int port)`:

创建连接到指定远程主机远程端口的Socket
该构造器没有指定本地地址本地端口
本地IP地址端口使用默认值。**

- **`Socket(InetAddress/String remoteAddress, int port, InetAddress localAddr, int localPort)`:

创建连接到指定远程主机远程端口Socket
并指定本地IP地址本地端口号
适用于本地主机多个IP地址的情形。**

  • **在使用上述构造器指定远程主机时,

既可使用InetAddress来指定,也可以使用String对象指定,
Java中通常使用String对象指定远程IP,例如192.168.2.23
当本地主机只有一个IP地址时,建议使用第一个方法,简单方便。
例如下面的代码:**

    //创建连接到本机、30000端口的Socket
    Socket s = new Socket("127.0.0.1" , 30000);
  • **当程序执行上述代码后会连接到指定服务器

服务器端ServerSocket的方法accept()向下执行,
于是服务器端客户端就产生一对互相连接的Socket
上述代码连接到“远程主机”的IP地址是127.0.0.1
IP地址总是代表本机的IP地址
这里例程的服务器端客户端都是在本机运行,
所以Socket连接到远程主机IP地址使用127.0.0.1。**

  • **当客户端服务器端产生对应的Socket之后,

程序无须再区分服务器端和客户端,
而是通过各自的Socket进行通信。**

  • Socket中提供如下两个方法获取输入流输出流

    • InputStream getInputStream()

返回该Socket对象 对应的输入流
让程序通过该输入流从Socket中取出数据。

- `OutputStream getOutputStream()`:

返回该 Socket对象 对应的输出流
让程序通过该输出流Socket输出数据

  • TCP协议的服务器端例程:
public class Server
{
    public static void main(String[] args)
        throws IOException
    {
        //创建一个ServerSocket,用于监听客户端Socket的连接请求
        ServerSocket myss = new ServerSocket(30001);
        //采用循环不断接受来自客户端的请求
        while (true)
        {
          //每当接受到客户端Socket的请求,服务器端也对应产生一个Socket
          Socket s = myss.accept();
          //将Socket对应的输出流包装成PrintStream
          PrintStream ps = new PrintStream(s.getOutputStream());
          //进行普通IO操作
          ps.println("凌川江雪!");
          ps.println("望川霄云!");
          ps.println("万年太久,只争朝夕!");
          ps.println("人间正道是沧桑!");
          ps.println("穷善其身,达济天下!");
          
          //关闭输出流,关闭Socket
          ps.close();
          s.close();
        }
    }
}
  • 上述代码建立了ServerSocket监听

并且使用Socket获取了输出流
执行后不会显示任何信息。

  • 对应的TCP协议的客户端例程:
public class Client {

    public static void main(String[] args)  throws IOException
    {
        Socket socket = new Socket("127.0.0.1" , 30001);
        //将Socket对应的输入流包装成BufferedReader
        BufferedReader br = new BufferedReader(
          new InputStreamReader(socket.getInputStream()));
        
        //进行普通IO操作         
        StringBuilder response = new StringBuilder();
        String line;
        
        //一行一行地读取并加进stringbuilder
        while((line = br.readLine()) != null){
            response.append(line + "\n");
        }
        
        System.out.println("来自服务器的数据:" + "\n" + response.toString());  
        
        //关闭输入流、Socket
        br.close();
        socket.close();
    }

}
  • 上述代码使用Socket建立了与指定IP、指定端口的连接,

并使用Socket获取输入流读取数据,
之后处理一下数据然后打印在工作台。
运行服务端Class运行客户端Class,运行结果:

  • 由此可见,

一旦使用ServerSocketSocket建立网络连接之后,
程序通过网络通信普通IO并没有太大的区别。
如果先运行上面程序中的Server 类,
将看到服务器一直处于等待状态
因为服务器使用了死循环来接受来自客户端的请求;
再运行Client类,
将可看到程序输出“来自服务器的数据:...!”,
这表明客户端和服务器端通信成功





TCP中的多线程

  • **刚刚实操的例程中,

ServerClient只是进行了简单的通信操作,
当服务器接收到客户端连接之后,服务器向客户端输出一个字符串,
客户端也只是读取服务器的字符串退出了。**

  • **在实际应用中,

客户端可能需要和服务器端保持长时间通信
服务器需要不断读取客户端数据
向客户端写入数据,
客户端也需要不断读取服务器数据,
向服务器写入数据。**

  • **当使用readLine()方法读取数据时,

如果在该方法成功返回之前线程阻塞,则程序无法继续执行
所以服务器很有必要为每个Socket 单独启动一条线程
每条线程 负责与一个客户端进行通信。**

  • **另外,

因为客户端读取服务器数据线程同样会被阻塞
所以系统应该单独 启动一条线程
该组线程专门负责读取服务器数据。**

  • **假设要开发一个聊天室程序

服务器端应该包含多条线程
其中每个Socket对应一条线程

线程负责
读取 Socket 对应输入流数据
(从客户端发送过来的数据),

并将读到的数据
每个Socket输出流发送一遍
(将一个客户端 发送的数据 “广播” 其他客户端 );**

  • **因此需要在服务器端使用List保存所有的Socket

具体实现时,
服务器提供了如下两个类
创建ServerSocket监听主类
处理每个Socket通信线程类。**

1/4 接下来介绍具体实现流程,首先看下面的IServer Class:

public class IServer
{
    //定义保存所有Socket的ArrayList
    public static ArrayList<Socket> socketList = new ArrayList<Socket>();

    public static void main(String[] args) 
        throws IOException
    {
        ServerSocket ss = new ServerSocket(30000);
        while(true)
        {
            //此行代码会阻塞,将一直等待别人的连接
            Socket s = ss.accept();
            socketList.add(s);
            //每当客户端连接后启动一条ServerThread线程为该客户端服务
            new Thread(new Serverxian(s)).start();
        }
    }
}
** IServer类中,
服务器端(ServerSocket )只负责接受 客户端Socket连接请求
每当 客户端Socket连接到该 ServerSocket之后,
程序将 客户端对应的Socket(客户Socket的对面一端)加入 socketList集合保存
并为该 Socket启动一条 线程Serverxian),
线程负责 处理 该Socket所有 的 通信任务
小结:
IServer类完成的业务是:
1.接收 客户端Socket
2.保存 对应返回的Socket
3.启动 处理线程。**

2/4 接着看服务器端线程类文件:

package liao.server;
import java.io.*;
import java.net.*;
import java.util.*;

//负责处理每个线程通信的线程类
public class Serverxian implements Runnable 
{
    //定义当前线程所处理的Socket
    Socket s = null;
    
    //该线程所处理的Socket所对应的输入流读取器
    BufferedReader br = null;
    
    public Serverxian(Socket s)
        throws IOException
    {
        this.s = s;
        //初始化该Socket对应的输入流
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    }
    
    public void run()
    {
        try
        {
            String content = null;
            
            //采用循环不断从Socket中读取客户端发送过来的数据
            while ((content = readFromClient()) != null)
            {
                
                //遍历socketList中的每个Socket,
                //将读到的内容向每个Socket发送一次
                for (Socket s : IServer.socketList)
                {
                     //将Socket对应的输出流包装成PrintStream
                    PrintStream ps = new PrintStream(s.getOutputStream());
                    ps.println(content);
                }
            }
        }
        catch (IOException e)
        {
            //e.printStackTrace();
        }
    }
    
    //定义读取客户端数据的方法
    private String readFromClient()
    {
        try
        {
            return br.readLine();    
        }
        //如果捕捉到异常,表明该Socket对应的客户端已经关闭
        catch (IOException e)
        {
            //删除该Socket。
            IServer.socketList.remove(s);
        }
        return null;
    }
}
Serverxian类(服务器端线程类)中,
注意是线程类,继承Runnable,重写run方法
会不断读取客户端数据,

在获取时使用方法readFromClient()来读取客户端数据。
如果读取数据过程中捕获到 IOException异常,
则说明此Socket对应的客户端Socket出现了问题,
程序就会将此Socket从socketList中删除。

当服务器线程读到客户端数据之后会遍历整个socketList集合,
并将该数据向socketList集合中的每个Socket发送一次,
该服务器线程将把从Socket中读到的数据
向socketList中的每个Socket转发一次。

  • **上述代码能够不断获取Socket输入流中的内容,

当获取Socket输入流中的内容后,
直接将这些内容打印在控制台

先运行上面程序中的类IServer
该类运行后作为本应用的服务器,不会看到任何输出。接着可以运行多个 IClient——相当于启动多个聊天室客户端登录该服务器,此时在任何一个客户端通过键盘输入一些内容后单击“回车”键,将可看到所有客户端(包括自己)都会在控制台收到刚刚输入的内容,这就简单实现了一个聊天室的功能。**

  • **运行结果如下动图所示:

[(这个链接是
在Eclipse上,同时运行多个java程序,
用不同的console显示运行信息的方法)](https://blog.csdn.net/dear_alice_moon/article/details/78274538)
图中展现的是:已经启动服务端,
同时启动两个客户端,
来回切换客户端进行“聊天”,
客户端由于服务端的socket传输,
可以相互收到彼此的信息;**

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
相关文章
|
14天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
14天前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。
|
22天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
14天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
38 6
|
1天前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
2天前
|
移动开发 Java Android开发
构建高效Android应用:采用Kotlin协程优化网络请求
【4月更文挑战第24天】 在移动开发领域,尤其是对于Android平台而言,网络请求是一个不可或缺的功能。然而,随着用户对应用响应速度和稳定性要求的不断提高,传统的异步处理方式如回调地狱和RxJava已逐渐显示出局限性。本文将探讨如何利用Kotlin协程来简化异步代码,提升网络请求的效率和可读性。我们将深入分析协程的原理,并通过一个实际案例展示如何在Android应用中集成和优化网络请求。
|
6天前
|
监控 Java 开发者
深入理解 Java 网络编程和 NIO
【4月更文挑战第19天】Java网络编程基于Socket,但NIO(非阻塞I/O)提升了效率和性能。NIO特点是非阻塞模式、选择器机制和缓冲区,适合高并发场景。使用NIO涉及通道、选择器和事件处理,优点是高并发、资源利用率和可扩展性,但复杂度、错误处理和性能调优是挑战。开发者应根据需求选择是否使用NIO,并深入理解其原理。
|
8天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
9天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
10 0
|
9天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
9 0