Android网络 | Socket(Eclipse--Java)

简介: 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传输,
可以相互收到彼此的信息;**

相关实践学习
自建数据库迁移到云数据库
本场景将引导您将网站的自建数据库平滑迁移至云数据库RDS。通过使用RDS,您可以获得稳定、可靠和安全的企业级数据库服务,可以更加专注于发展核心业务,无需过多担心数据库的管理和维护。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
相关文章
|
存储 监控 安全
单位网络监控软件:Java 技术驱动的高效网络监管体系构建
在数字化办公时代,构建基于Java技术的单位网络监控软件至关重要。该软件能精准监管单位网络活动,保障信息安全,提升工作效率。通过网络流量监测、访问控制及连接状态监控等模块,实现高效网络监管,确保网络稳定、安全、高效运行。
642 11
|
11月前
|
JSON 移动开发 网络协议
Java网络编程:Socket通信与HTTP客户端
本文全面讲解Java网络编程,涵盖TCP与UDP协议区别、Socket编程、HTTP客户端开发及实战案例,助你掌握实时通信、文件传输、聊天应用等场景,附性能优化与面试高频问题解析。
|
9月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
429 1
|
9月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
396 1
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
378 9
|
9月前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
741 0
|
API 数据处理 Android开发
Android网络请求演变:从Retrofit到Flow的转变过程。
通过这个比喻,我们解释了 Android 网络请求从 Retrofit 到 Flow 的转变过程。这不仅是技术升级的体现,更是反映出开发者在面对并发编程问题时,持续探索和迭求更好地解决方案的精神。未来,还会有更多新的技术和工具出现,我们期待一同 witness 这一切的发展。
587 36
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
687 23
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
625 15
|
Web App开发 缓存 JavaScript
Android网络小说阅读器的实现
小说阅读Demo,。此Demo使用Jsoup解析HTML,实现小说数据抓取(数据源自网络),并包含自定义View、六章小说缓存等功能,但未实现下载。项目还包括屏幕适配、字体设置等,借助第三方框架完成优化。以下是主页、详情页、阅读页等界面展示。
429 0