Java 网络编程 —— Socket 详解

构造 Socket

在【客户端/服务端】的通信模式中,客户端需要主动构造与服务器连接的 Socket,构造方法有以下几种重载形式:

Socket()
Socket(InetAddress address, int port) throws UnknownHostException,IOException
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
Socket(String host, int port) throws UnknownHostException,IOException
Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
Socket(Proxy proxy)

除了第一个不带参数的构造方法,其他构造方法都会试图建立与服务器的连接,一旦连接成功,就返回 Socket 对象,否则抛出异常

1. 设定等待建立连接的超时时间

当客户端的 Socket 构造方法请求与服务器连接时,可能要等待一段时间。在默认情况下,Socket 构造方法会一直等待下去,直到连接成功,或者出现异常。Socket 构造方法请求连接时,受底层网络的传输速度的影响,可能会处于长时间的等待状态。如果希望限定等待连接的时间,就需要使用第一个不带参数的构造方法

Socket socket = new Socket();
SocketAddress remoteAddr = new InetSocketAddress("1ocalhostn", 8000);
// 参数endpoint指定服务器的地址,参数timeout设定的超时时间(ms)
// 如果参数timeout被设为0则表示永远不会超时
socket.connect(remoteAddr, 60000);

以上代码用于连接到本地机器上的监听 8000 端口的服务器程序,等待连接的最长时间为一分钟。如果在一分钟内连接成功,则 connect() 方法顺利返回,如果在一分钟内出现某种异常则抛出该异常,如果在一分钟后既没有连接成功,也没有出现异常,那么会抛出 SocketTimeoutException

2. 设定服务器的地址

除了不带参数的构造方法,其他构造方法都需要在参数中设定服务器的地城,包括服务器的 IP 或主机名,以及端口

// address表示主机的IP地址
Socket(InetAddress address, int port)
// address表示主机的名字
Socket(String host, int port)

InetAddress 类表示主机的P地址,提供了一系列静态工厂方法用于构造自身实例

// 返回本地主机的IP地址、
InetAddress addr1 = inetAddress.getLocalHost();
// 返回代表 "222.34.57” 的 IPv4 地址
InetAddress addr2 = InetAddress.getByName("222.34.5.7");
// 返同代表 ”2001:DB8:2DE::E13" 的 IPv6 地址
InetAddress addr3 = InetAddress.getByName("2001:DB8:2DE::E13");
// 返回主机名为 "www.javathinker.net" 的 IP 地址
InetAddress addr4 = InetAddress.getByName ("www.javathinker.net");
3. 设定客户端的地址

在一个 Socket 对象中既包含远程服务器的 IP 地址和端口信息,也包含本地客户端的 IP 地址和端口信息。在默认情况下,客户端的 IP 地址来自客户程序所在的主机,客户端的端口则由操作系统随机分配。Socket 类还有两个构造方法允许显式地设置客户端的 IP 地址和端口

Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

如果一个主机同时属于两个以上的网络,它就可能拥有两个以上 IP 地址,例如一个主机在 Internet 网络中的 IP 地址为 “222.67,1.34”,在一个局域网中的 IP 地址为 “1125.4.3",假定这个主机上的客户程序希望和同一个局城网上的一个地址为 “112.5.4.4:8000” 的服务器程序通信,客户端可按照如下方式构造 Socket 对象

InetAddress remoteAddr = InetAddress.getByName("112.5,4.45");
InetAddress localAddr = InetAddress.getByName("112.5.4.3");
//客户端使用口2345
Socket socket = new Socket(remoteAddr, 8000, localAddr, 2345);
4. 客户连接服务器时可能抛出的异常

当 Socket 的构造方法请求连接服务器时,可能会抛出以下异常:

  • UnknownHostException:无法识别主机的名字或 IP 地址
  • ConnectException:没有服务器进程监听指定的端口,或者服务器进程拒绝连接
  • SocketTimeoutException:等待连接超时
  • BindException:无法把Socket 对象与指定的本地 IP 地址或端口绑定
5. 使用代理服务器

在实际应用中,有的客户程序会通过代理服务器来访问远程服务器。代理服务器有许多功能,比如能作为防火墙进行安全防范,或者提高访问速度,或者具有访问特定远程服务器的权限

String proxyIP = "myproxy.abc.oom"; // 代理服务器地址
int proxyPort = 1080; // 代理服务器端口
// 创建代理对象
Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(proxyIP, proxyPort));
Socket socket  new Socket(proxy);
//连接到远程服务器
socket.connect(new InetSocketAddress("www.javathinker.net", 80));

ProxyType 类表示代理服务器的类型,有以下可选值:

  • Proxy.Type.SOCKS:在分层的网络结构中,SOCKS 是位于会话层的代理类型
  • Proxy.Type.HTTP:在分层的网络结构中,HTTP 是位于应用层的代理类型
  • Proxy.Type.DIRECT:不使用代理,直接连接远程服务器
6. InetAddress 地址类的用法

InetAddress 类表示主机的IP 地址,InetAddress 类的静态工厂方法给 getByName() 用于构造自身的实例

// 返回代表 "222.34.5.7" 的 IPv4 地址
InetAddress addr2 = InetAddress,getByName("222.34.5.7");
// 返回主机名为 "www.javathinker.net" 的 IP 地址
InetAddress addr4 = InetAddress.getByName("www.javathinker.net");

InetAddress 还提供了获取相应的主机名的两种方法:

  • getHostname():首先从 DNS 缓存中查找与 IP 地址匹配的主机名,如果不存在,再通过 DNS 服务器查找,如果找到,则返回主机名,否则返回 IP 地址
  • getCanonicalHostName():通过 DNS 服务器查找与 IP 地址匹配的主机名,如果找到则返回主机名,否则返问 IP 地址

以上两种方法的区别在于 getHostname() 会先查找 DNS 缓存,减少查找 DNS 服务器的概率,提高查找性能。而 getCanonicalHostName() 总是查找 DNS 服务器,确保获得当前最新版本的主机名

InetAddress 类还提供了两个测试能否从本地主机连接到特定主机的方法:

public boolean isReachable(int timeout) throws IOException
public boolean isReachable(NefworkInterface interface, int ttl, int timeout) throws IOException

如果远程主机在参数 timeout(ms)指定的时间内做出回应,以上方法返回true,否则返回 false,如果出现网络错误则抛出 IOException。第二种方法还允许从参数指定的本地网络接口建立连接,以及 TTL(IP 数据包被丢弃前允许存在的时间)

7. NetworkInterface 类的用法

NetworkInterfiace 类表示物理上的网络接口,它有两种构造自身实例的静态工厂方法,这两种方法都声明抛出 SocketException

// 参数 name 指定网络接口的名字,如果不存在与名字对应的网络接口,就返回 null
getByName(String name)
// 参数 address 指定网络接口的 IP 地址,如果不存在与 IP 地址对应的网络接口,就返回 null
getByInetAddress(InetAddress address)

NetworkInterface 类的以下方法用于获取网络接口的信息

// 返回网络接口的名字
public String getName()
// 返回和网络接口绑定的所有 IP 地址,返回值为 Enumeration 类型,里面存放了表示 IP 地址的 InetAddress 对象
public Enumeration getInetAddresses()

获取 Socket 的信息

在一个 Socket 对象中同时包含了远程服务器的 IP 地址和端口信息,以及客户本地的 IP 地址和端口信息。此外,从 Socket 对象中还可以获得输出流和输入流,分别用于向服务器发送数据,以及接收从服务器端发来的数据

以下方法用于获取 Socket 的有关信息

// 获得远程被连接进程的IP地址
getInetAddress()
// 获得远程被连接进程的端口
getPort()
// 获得本地的IP地址
getLocalAddress()
// 获得本地的端口
getLocalPort()
// 获得输入流,如果Socket还没有连接,或者已经关团,或者已经通过shutdownInput()方法关闭输入流,那么此方法会抛出IOException
getInputStream()
// 获得输出流,如果Socket还没有连接,或者已经关闭,或者已经通过shutdownOutput()方法关闭输出流,那么此方法会抛出 IOException
getOutputStream()

关闭 Socket

当客户与服务器的通信结束时,应该及时关闭 Socket,以释放 Socket 占用的包括端口在内的各种资源。Socket 的 close() 方法负责关闭 Socket,如果一个 socket 对象被关闭,就不能再通过它的输入流和输出流进行 IO 操作,否则会导致 IOException

Socket 类提供了三个状态测试方法

// 如果Socket没有关闭,则返回false,否则返回true
isClosed()
// 如果Socket曾经连接到远程主机,不管当前是否已经关闭,都返回true。如果Socket从未连接到远程主机,就返回false
isConnected()
// 如果Socket已经与一个本地端口绑定,则返回true,否则返回false
isBound()

如果要判断一个 Socket 对象当前是否处于连接状态,可采用以下方式

String isConnected = socket.isConnected() && !socket.isClosed();

半关闭 Socket

进程 A 与进程 B 通过 Socket 通信,假定进程 A 输出数据,进程 B 读入数据,进程 A 如何告诉进程 B 所有数据已经输出完毕呢?有几种处理办法:

  • 如果进程 A 与进程 B 交换的是字符流,并且都一行一行地读写数据,那么可以事先约定以一个特殊的标志作为结束标志,例如以字符串 “bye” 作为结束标志,当进程 A 向进程 B 发送一行字符串 “bye”,进程 B 读到这一行数据后,就停止读取数据

  • 进程 A 先发送一个消息,告诉进程 B 所发送的正文的长度,然后发送正文。进程 B 先获知进程 A 将发送的正文的长度,接下来只要读取该长度的字符或者字节,就停止读取数据

  • 进程 A 发完所有数据后,关闭 Socket,当进程 B 读入了进程 A 发送的所有数据后,再次执行输入流的 read() 方法时,该方法返回 “-1”,如果执行 BufferedReader 的 readLine() 方法,那么该方法返回 null

    ByteArrayOutputstream bufferenew = ByteArrayOutputstream();
    byte[] buff = new byte[1024);
    int len = -1;
    while((len = socketIn.read(buff)) != -1) {
        buffer.write(buff, 0, len);   
    }
    
  • 当调用 Socke t的 close() 方法关闭 Socket 后,它的输出流和输入流也都被关闭。有的时候,可能仅仅希望关闭输出流或输入流之一,此时可以采用 Socket 类提供的半关闭方法

    shutdownInput() // 关闭输入流
    shutdownOutput() // 关团输出流
    

    假定进程 A 执行以下代码,先向进程 B 发送一个字符串,等到进程 B 接收到这个字符串后,进程 A 再调用 Socket 的 shutdownOutput() 方法关闭输出流,接下来进程 A 不允许再输出数据,但是仍可以通过输入流读入数据

    // 发出请求信息
    String data = ...;
    OutputStream socketOut = socket.getOutputStream();
    socketOut.write(data.getBytes());
    socketOut.flush();
    // 读取响应
    InputStream socketIn = socket.getInputStream();
    if(服务器端返回提示信息,表明已经接收到客户端的所有请求数据)
        socket.shutdownOutput(); //关闭输出流
    //继续通过socketIn读取数据
    ...
    

    值得注意的是,先后调用 Socket 的 shutdownInput() 和 shutdownOutput() 方法,仅仅关闭了输入流和输出流,并不等价于调用 Socket 的 close() 方法。在通信结束后,仍然要调用 Socket 的 close() 方法,因为只有该方法才会释放 Socket 占用的资源,比如占用的本地端口等

    Socket 类还提供了两种状态测试方法,用来判断输入流和输出流是否关闭

    public boolean isInputShutdown() // 如果输入流关闭,则返回true,否则返回false
    public boolean isOutputShutdown() // 如果输出流关闭,则返回true,否则返回false
    

设置 Socket 的选项

1. TCP_NODELAY

表示立即发送数据。在默认情况,下发送数据采用 Negale 算法,发送方发送的数据不会立刻被发出,而是先放在缓冲区内,等缓冲区满了再发出。发送完一批数据后,会等待接收方对这批数据的回应,然后发送下一批数据。此算法法适用于发送方需要发送大批量数据并且接收方会及时做出回应的场合,这种算法通过减少传输数据的次数来提高通信效率

如巢发送方持续地发送小批量的数据。并且接收方不一定会立即发送响应数据,那么 Negale 算法会使发送方运行得很慢,对于GU程序,比如网络游戏程序(服务器需要实时跟踪客户端鼠标的移动),这个问题尤其突出

TCP_NODEALY 的默认值为 false,表示采用 Negale 算法,如果调用 setTcpNoDelay(true) 方法,就会关闭 Socket 的缓冲,确保数据被及时发送

if(!socket.getTcpNoDelay())
    socket.setTcpNoDelay(true);
2. SO_RESUSEADDR

表示是否允许重用 Socket 所绑定的本地地址。当接收方通过 Socket 的 close() 方法关闭 Socket 时,如果网络上还有发送到这个 Socket 的数据,那么底层的 Socket 不会立刻释放本地端口,而是会等待一段时间,确保接收到了网络上发送过来的延迟数据,再释放端口。Socket 接收到延迟数据后,不会对这些数据做任何处理。Socket 接收延迟数据的目的是,确保这些数据不会被其他碰巧绑定到同样端口的新进程接收到

客户程序一般采用随机端口,因此出现两个客户程序绑定到同样端口的可能性不大。许多服务器程序都使用固定的端口。当服务器程序被关闭后,有可能它的端口还会被占用一段时间,如果此时立刻在同一台主机上重启服务器程序,由于端口已经被占用,使得服务感程序无法绑定到该端口,导致启动失败

为了确保当一个进程关闭了 Socket 后,即便它还没释放端口,同一台主机上的其他进要也可以立刻重用该端口,可以调用 Socke 的 setResuseAddress(ture) 方法

if(!socket.getResuseAddress())
    socket.setResuseAddress(true);

值得注意的是 socket.setResuseAddress(true) 方法必须在 Socket 还没有被绑定到一个本地端口之前调用,否则执行无效

3. SO_TIMEOUT

表示接收数据时的等待超时时间。当通过 Socket 的输入流读数据时,如果还没有数据,就会等待。Socket 类的SO_TIMEOUT 选项用于设定接收数据的等待超时时间,单位为 ms,它的默认值为0,表示会无限等待,永远不会超时

以下代码把接收数据的等待超时时间设为三分钟

if(socket.getTimeout() == 0)
    socket.setTimeout(60000 * 3);

Socket 的 setTimeout() 方法必须在接收数据之前执行才有效

4. SO_LINGER

表示与执行 Socket 的 close() 方法时,是否立即关闭底层的 Socket。在默认情况下执行 Socket 的 close() 方法,该方法会立即返回,但底层的 Socket 实际上并不立即关闭,它会延迟一段时间,直到发送完所有剩余的数据,才会真正关闭 Socket

如果执行以下方法

socket.setSoLinger(true,0);

那么执行 Socket 的 close() 方法,该方法也会立即返回而且底层的 Socket 也会立即关闭,所有未发送完的数据被丢弃

如果执行以下方法

socket.setSoLinger(true,3600);

那么执行 Socket 的 close() 方法,该方法不会立即返回,而是进入阻塞状态,同时,底层的 Socket 会尝试发送剩余的数据。只有满足以下两个条件之一,close() 方法才返回:

  • 底层的 Socket 已经发送完所有的剩余数据
  • 尽管底层的 Socket 还没有发送完所有的剩余数据,但己经阻塞了 3600s,此时 close() 也会返回,未发送的数据被丢弃
5. SO_RCVBUF

表示接收数据的缓冲区的大小。一般说来,传输大的连续的数据块,比如基于 HTTP 或 FTP 的通信,可以使用较大的缓冲区,这可以减少传输数据的次数,提高传输数据的效率。而对于交互式的通信方式,比如 Telnet 和网络游戏,则应该采用小的缓冲区,确保小批量的数据能及时发送给对方

6. SO_SNDBUF

表示发送数据的缓冲区的大小

7. SO_KEEPALIVE

表示对于长时间处于空闲状态的 Socket,是否要自动把它关团。当 SO_KEEPALIVE 选项为 tue 时,表示底层的 TCP 实现会监视该连接是否有效连接处于空闲状态,即连接的两端没有互相传送数据超过了 2 小时,本地的 TCP 实现发送一个数据包给远程的 Socket,如果远程 Socke 没有返回响应,TCP 实现就会持续尝试发送 11 分钟,直到接收到响应为止。如果在 12 分钟内未收到响应,TCP 实现就会自动关闭本地 Socket,断开连接

SO_KEEPALIVE 选项的默认值为 false,表示 TCP 不会监视连接是否有效,不活动的客户端可能会永久存在下去,而不会注意到服务器已经崩溃

8. IP 服务类型选项

当用户通过邮局发送普通信、挂号信或者快件时,实际上选择了邮局提供的不同的服务。发送普通信的价格最低,但发送速度慢,并且可靠性没有保证。发送挂号信的价格稚高,但可靠性有保证。发送快件的价格最高,发送速度最快,并且可靠性有保证

在 Internet 上传输数据也分为不同的服务类型,它们有不同的定价。用户可以根据自己的需求,选择不同的服务类型。例如发送视频需要较高的带宽,快速到达目的地,以保证接收方看到连续的画面,而发送电子邮件可以使用较低的带宽,延迟几个小时到达目的地也没关系

IP 规定了一些服务类型,用来定性地描述服务的质量,举例如下:

  • 低成本:发送成本低
  • 高可靠性:保证把数据可靠地送达目的地
  • 最高吞吐量:一次可以接收或发送大批量的数据
  • 最小延迟:传输数据的速度快,把数据快速送达目的地

这些服务类型还可以进行组合,例如,可以同时要求获得高可靠性和最小延迟。服务类型存储在 IP 数据包头部的名为 IP_TOS 的 8 位字段中,Socket 类中提供了设置和读取服务类型的方法

// 设置服务类型
public void setTrafficClass(int trafficClass) throws SocketException
// 读取服务类型
public int getTrafficClass() throws SocketException

服务类型用 1 字节来表示,取值范围是 0 到 255 之间的整数。这个服务类型数据也会被复制到 TCP 数据包头部的 8 位字段中。,在目前的网络协议中,对这个表示服务类型的字节又做了进一步的细分:

  • 高六位:表示 DSCP 值,即表示不同的服务类型代码号。DSCP 允许最多有 64 种服务类型
  • 低两位:表示 ECN 值,即显式拥塞通知信息

64 个 DSCP 值到底表示什么含义,这是由具体的网络和路由器决定的。下面是比较常见的 DCSP 值:

  • 默认服务类型:000000

  • 加速转发类型:101110,特点是低损耗、低延迟、低抖动

  • 保证转发类型:共 12 个取值,保证以指定速率传送,见下表

    类型第1类(最低转发优先)第2类第3类第4类(最高转发优先)
    低丢包率001010010010011010100010
    中丢包率001100010100011100100100
    高丢包率001110010110011110100110

    其中第 1 类有最低转发优先级,第 4 类有最高转发优先级。也就是说,当网络出现阻塞时,第 4 类的数据包被优先转发。每一类又包含了 3 个取值,其中低丢包率的服务类型丢弃数据包的概率小,而高丢包率的服务类型丢弃数据包的概率大

加速转发类型比其他服务类型有更高的优先级,例如以下代码使得 Socket 采用加速转发类型来收发数据:

Socket socket = new Socket("www.javathinker.net", 80);
// 0xB8 对应二进制数据 10111000
// 低两位表示显式拥塞通知,取值为 00
socket.setTrafficClass(0xB8);

值得注意的是,DCSP 值仅仅为底层的网络实现提供一个参考,有些底层 Socket 实现会忽略 DCSP 值,对它不进行任何处理

9. 设定连接时间、延迟和带宽的相对重要性

从 JDK1.5 开始,为 Socket 类提供了一个 setPerformancePreferences() 方法

public vold setPerformancePreferences (int connectionTime, int latency, int bandwidth)

以上方法的 3 个参数表示网络传输数据的 3 项指标:

  • connectionTime:表示用最少时间建立连接
  • latency:表示最小廷迟
  • bandwidth:表示最高带宽

setPerformancePreferences() 方法被用来设定这 3 项指标之间的相对要性。可以为这些参数赋予任意的整数。这些整数之间的相对大小就决定了相应参数的相对重要性。例如,如果参数 connectionTime 为 2,参数 latency 为 1,而参数 bandwidth 为 3,就表示最高带宽最重要,其次是最少连接时间,最后是最小延迟

值得注意的是 setPerformancePreferences() 方法所做的设置仅仅为底层的网络实现提供一个参考,有些底层 Socket 实现会忽略这一设置,对它不进行任何处理


  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者简介   杨丰盛,Android应用开发先驱,对Android有深入研究,实战经验极其丰富。精通Java、C、C++等语言,专注于移动通信软件开发,在机顶盒软件开发和MTK平台软件开发方面有非常深厚的积累。2007年获得中国软件行业协会游戏软件分会(CGIA)认证及国际游戏开发教育联合会国际认证。曾经领导和参与《三国群英传说》、《大航海传奇》、《美少女养成计划》等经典游戏的开发。 编辑本段 图书目录   前言   第一部分 准备篇   第1章 Android开发简介   1.1 Android基本概念   1.1.1 Android简介   1.1.2 Android的系统构架   1.1.3 Android应用程序框架   1.2 OMS介绍   1.2.1 OPhone介绍   1.2.2 Widget介绍   1.3 小结   第2章 Android开发环境搭建   2.1 Android开发准备工作   2.2 开发包及其工具的安装和配置   2.2.1 安装JDK和配置Java开发环境   2.2.2 Eclipse的安装与汉化   2.2.3 SDK和ADT的安装和配置   2.3 创建第一个Android项目——HeUoAndroid   2.3.1 创建HelloAndroid项目   2.3.2 运行HelloAndroid及模拟器的使用   2.3.3 调试HelloAndroid   2.4 小结   第二部分 基础篇   第3章 Android程序设计基础   3.1 Android程序框架   3.1.1 Android项目目录结构   3.1.2 Android应用解析   3.2 Android的生命周期   3.3 Android程序U设计   3.4 小结   第4章 用户界面开发   4.1 用户界面开发详解   4.1.1 用户界面简介   4.1.2 事件处理   4.2 常用控件应用   4.2.1 文本框(Textiew)   4.2.2 列表(ListView)   4.2.3 提示(T0ast)   4.2.4 编辑框(EditText)   4.2.5 单项选择(RadioGroup、RadioButton   4.2.6 多项选择(CheckBox)   4.2.7 下拉列表(Spinner)   4.2.8 自动提示(AutoComplete.TextⅥew)   4.2.9 日期和时间(DatePicker、TimePicker)   4.2.10 按钮(Button)   4.2.1l 菜单(Menu)   4.2.12 对话框(Dialog)   4.2.13 图片视图(ImageView)   4.2.14 带图标的按钮(ImageButton)   4.2.15 拖动效果(Gallery)   4.2.16 切换图片(hmgeSwilcher)   4.2.17 网格视图(GridView)   4.2.18 卷轴视图(ScrollView)   4.2.19 进度条(ProgressBar)   4.2.20 拖动条(SeekBar)   4.2.21 状态栏提示(Notification、NotificationManager)   4.2.22 对话框中的进度条(ProgressDialog)   4.3 界面布局   4.3.1 垂直线性布局   4.3.2 水平线性布局   4.3.3.相对布局(RelativeLayout)   4.3.4 表单布局(TableLayout)   4.3.5 切换卡(TabWidget)   4,4 小结   第5章 Android游戏开发   5.1 Android游戏开发框架   5.1.1 View类开发框架   5.1.2 SurfaceView类开发框架   5.2 Graphics类开发   5.5.1 Paint和Color类介绍   5.2.2 Canvas类介绍   5.2.3 几何图形绘制   5.2.4 字符串绘制   5.2.5 图像绘制   5.2.6 图像旋转   5.2.7 图像缩放   5.2.8 图像像素操作   5.2.9 Shader类介绍   5.2.10 双缓冲技术   5.2.11 全屏显示   5.2.12 获得屏幕属性   5.3 动画实现   5.3.1 Tween动画   5.3.2 Frame动画   5.3.3 GIF动画播放   5.4 小结   第6章 Android数据存储   6.1 Android数据存储初探   6.2 数据存储之Shared Preferences   6.3 数据存储之Files   6.4 数据存储之Network   6.5 Android数据库编程   6.5.1 SQLite简介   6.5.2 SQLite编程详解   6.5.3 SQLiteOpenHelper应用   6.6 数据共享(ContentProviders)   6.7 小结   第7 章多媒体开发   7.1 多媒体开发详解   7.1.1 Open Core   7.1.2 MediaPlayer   7.1.3 MediaRecorder   7.2 播放音乐   7.3 播放视频   7.4 录制歌曲   7.5 相机设置   7.6 闹钟设置   7.7 铃声设置   7.8 小结   第8章 网络与通信   8.1 网络通信基础   8.1.1 无线网络技术   8.1.2 Android网络基础   8.2 HTTP通信   8.2.1 HttpURLConnection接口   8.2.2 HttpClient接口   8.2.3 实时更新   8.3 Socket通信   8.3.1 Socket基础   8.3.2 Socket应用(简易聊天室)   8.4 网络通信的中文乱码问题   8.5 WebKit应用   8.5.1 WebKjt概述   8.5.2 WebView浏览网页   8.5.3 WebView与Javascript   8.6 WtFi介绍   8.7 蓝牙   8.8 小结   第9章 Android特色开发   9.1 传感器   9.2 语音识别   9.3 GoogleMap   9.3.1 GoogleMap概述   9.3.2 准备工作   9.3.3 GoogleMapAPI的使用   9.3.4 定位系统   9.4 桌面组件   9.4.1 快捷方式   9.4.2 实时文件夹   9.4.3 Widget开发   9.5 账户管理   9.6 小结   第三部分 实例篇   第10章 Android应用开发实例   10.1 情境模式   10.2 文件管理器   10.3 通讯录   10.4 音乐播放器   10.5 天气预报   10.6 个人地图   10.7 Widget日历   10.8 小结   第11 章Android游戏开发实例   11.1 手机游戏开发简介   11.2 游戏框架设计   11.3 地图设计   11.4 主角设计   11.5 图层管理器   11.6 游戏音效   11.7 游戏存档   11.8 小结   第四部分 高级篇   第12章 AndroidOpenGL开发基础   12.1 OpenGL简介   12.2 多边形   12.3 颜色   12.4 旋转   12.5 3D 空间   12.6 纹理映射   12.7 光照和事件   12.8 混合   12.9 小结   第13章 AndroidOpenGL综合应用   13.1 移动图像   13.2.3D 世界   13.3 飘动的旗帜   13.4 显示列表   13.5 雾   13.6 粒子系统   13.7 蒙版   13.8 变形   13.9 小结   第14章 游戏引擎实现   14.1 游戏引擎介绍   14.1.1 什么是引擎   14.1.2 引擎的进化   14.1.3 常见的游戏引擎   14.1.4 Android游戏引擎   14.2 游戏引擎结构   14.2.1 游戏引擎原理   14.2.2 游戏引擎定位   14.2.3 游戏引擎框架   14.3 游戏引擎设计   14.3.1 游戏引擎结构和功能设计   14.3.2 游戏引擎设计注意事项   14.4 游戏引擎实现   14.4.1 Activity类实现   14.4.2 流程控制和线程   14.4.3 游戏对象与对象管理   14.4.4 图形引擎   14.4.5 物理引擎   14.4.6 事件模块   14.4.7 工具模块   14.4.8 脚本引擎、音效模块、网络模块   14.5 小结   第15章 优化技术   15.1 优化的基本知识   15.1.1 如何书写出优秀代码   15.1.2 编程规范   15.2 程序性能测试   15.2.1 计算性能测试   15.2.2 内存消耗测试   15.3 初级优化   15.4 高级优化   15.5 Android高效开发   15.6 AndroidUI优化   15.7 其他优化   15.7.1 zipalign   15.7.2 图片优化   15.8 小结   第五部分 扩展篇   第16章 Android NDK开发   16.1 AndroidNDK简介   16.2 安装和配置NDK开发环境   16.2.1 系统和软件需求   16.2.2 NDK开发环境搭建   16.2.3 编译第一个NDK程序   16.3 AndroidNDK开发   16.3.1 JNI接口设计   16.3.2 使用C\C++实现本地方法   16.3 编译C\C++代码   16.4 AndroidNDK中使用0penGL   16.5小结   第17章 Android脚本环境   17.1 Android脚本环境简介   17.2 Android脚本环境安装   17.3如何编写Android脚本程序   17.4小结
前言 第一部分 准备篇 第1章 Android开发简介 1.1 Android基本概念 1.1.1 Android简介 1.1.2 Android的系统构架 1.1.3 Android应用程序框架 1.2 OMS介绍 1.2.1 OPhone介绍 1.2.2 Widget介绍 1.3 小结 第2章 Android开发环境搭建 2.1 Android开发准备工作 2.2 开发包及其工具的安装和 配置 2.2.1 安装JDK和配置Java开发 环境 2.2.2 Eclipse的安装与汉化 2.2.3 SDK和ADT的安装和 配置 2.3 创建第一个Android项目——HeUoAndroid 2.3.1 创建HelloAndroid项目 2.3.2 运行HelloAndroid及模拟器的使用 2.3.3 调试HelloAndroid 2.4 小结 第二部分 基础篇 第3章 Android程序设计基础 3.1 Android程序框架 3.1.1 Android项目目录结构 3.1.2 Android应用解析 3.2 Android的生命周期 3.3 Android程序U设计 3.4 小结 第4章 用户界面开发 4.1 用户界面开发详解 4.1.1 用户界面简介 4.1.2 事件处理 4.2 常用控件应用 4.2.1 文本框(Textiew) 4.2.2 列表(ListView) 4.2.3 提示(T0ast) 4.2.4 编辑框(EditText) 4.2.5 单项选择(RadioGroup、RadioButton 4.2.6 多项选择(CheckBox) 4.2.7 下拉列表(Spinner) 4.2.8 自动提示(AutoComplete.TextⅥew) 4.2.9 日期和时间(DatePicker、TimePicker) 4.2.10 按钮(Button) 4.2.1l 菜单(Menu) 4.2.12 对话框(Dialog) 4.2.13 图片视图(ImageView) 4.2.14 带图标的按钮(ImageButton) 4.2.15 拖动效果(Gallery) 4.2.16 切换图片(hmgeSwilcher) 4.2.17 网格视图(GridView) 4.2.18 卷轴视图(ScrollView) 4.2.19 进度条(ProgressBar) 4.2.20 拖动条(SeekBar) 4.2.21 状态栏提示(Notification、NotificationManager) 4.2.22 对话框中的进度条(ProgressDialog) 4.3 界面布局 4.3.1 垂直线性布局 4.3.2 水平线性布局 4.3.3.相对布局(RelativeLayout) 4.3.4 表单布局(TableLayout) 4.3.5 切换卡(TabWidget) 4,4 小结 第5章 Android游戏开发 5.1 Android游戏开发框架 5.1.1 View类开发框架 5.1.2 SurfaceView类开发框架 5.2 Graphics类开发 5.5.1 Paint和Color类介绍 5.2.2 Canvas类介绍 5.2.3 几何图形绘制 5.2.4 字符串绘制 5.2.5 图像绘制 5.2.6 图像旋转 5.2.7 图像缩放 5.2.8 图像像素操作 5.2.9 Shader类介绍 5.2.10 双缓冲技术 5.2.11 全屏显示 5.2.12 获得屏幕属性 5.3 动画实现 5.3.1 Tween动画 5.3.2 Frame动画 5.3.3 GIF动画播放 5.4 小结 第6章 Android数据存储 6.1 Android数据存储初探 6.2 数据存储之Shared Preferences 6.3 数据存储之Files 6.4 数据存储之Network 6.5 Android数据库编程 6.5.1 SQLite简介 6.5.2 SQLite编程详解 6.5.3 SQLiteOpenHelper应用 6.6 数据共享(ContentProviders) 6.7 小结 第7 章多媒体开发 7.1 多媒体开发详解 7.1.1 Open Core 7.1.2 MediaPlayer 7.1.3 MediaRecorder 7.2 播放音乐 7.3 播放视频 7.4 录制歌曲 7.5 相机设置 7.6 闹钟设置 7.7 铃声设置 7.8 小结 第8章 网络与通信 8.1 网络通信基础 8.1.1 无线网络技术 8.1.2 Android网络基础 8.2 HTTP通信 8.2.1 HttpURLConnection接口 8.2.2 HttpClient接口 8.2.3 实时更新 8.3 Socket通信 8.3.
Java开发技术大全 电子版 第1篇Java基础知识入门. 第1章Java的开发运行环境2 1.1Java的运行环境与虚拟机2 1.2Java的开发环境4 1.2.1JDK的安装4 1.2.2如何设置系统环境变量6 1.2.3编译命令的使用8 1.2.4解释执行命令的使用10 1.2.5UltraEdit的使用11 1.3一个简单的Java应用程序14 1.4一个简单的Java小程序16 1.5本章小结18 第2章Java语言基础19 2.1Java语言的特点19 2.2Java程序的构成21 2.3数据类 型23 2.3.1基本数据类型23 2.3.2常量25 2.3.3变量26 2.3.4整型数据27 .2.3.5浮点型数据29 2.3.6字符型数据30 2.3.7布尔型数据32 2.3.8变量赋初值33 2.3.9变量的作用域34 2.3.10数据类型转换34 2.4运算符与表达式37 2.4.1算术运算符和算术表达式38 2.4.2关系运算符和关系表达式43 2.4.3逻辑运算符和逻辑表达式44 2.4.4条件运算符和条件表达式48 2.4.5位运算符和位运算表达式50 2.4.6赋值运算符和赋值表达式53 2.4.7表达式的求值顺序55 2.5流程控制语句58 2.5.1三种基本控制结构58 2.5.2表达式语句和空语句59 2.5.3块语句60 2.5.4if~else分支语句61 2.5.5多路分支switch~case语句69 2.5.6当型循环while语句71 2.5.7直到型循环do~while语句72 2.5.8当型循环for语句74 2.5.9循环的嵌套78 2.5.10跳转语句break80 2.5.11跳转语句continue82 2.6程序文本的风格84 2.6.1注释84 2.6.2程序的格式编排87 2.7基础语法实战演习88 2.7.1判断闰年88 2.7.2求最大公约数和最小公倍数89 2.7.3Fibonacci数列90 2.7.4逆向输出数字91 2.7.5求水仙花数92 2.7.6输出图形93 2.7.7输出九九口诀表94 2.8本章小结95 第2篇Java面向对象编程 第3章对象和类98 3.1面向对象的基本概念98 3.1.1对象98 3.1.2类99 3.1.3消息101 3.1.4面向对象的4个基本特征101 3.2类与对象104 3.2.1类的基本结构104 3.2.2类的声明104 3.2.3创建类体105 3.2.4对象的生命周期106 3.2.5对象的创建106 3.2.6对象的使用108 3.2.7对象的释放和垃圾收集机制108 3.3成员变量的定义与使用109 3.3.1成员变量的定义109 3.3.2成员变量的访问权限110 3.3.3实例成员变量和静态成员变量114 3.4方法的定义和实现116 3.4.1方法的声明117 3.4.2创建方法体与return语句117 3.4.3局部变量和成员变量的区别119 3.4.4方法的访问权限121 3.5方法的调用121 3.5.1方法调用的形式121 3.5.2方法调用的参数123 3.5.3隐含参数this127 3.6构造方法128 3.6.1无参数构造方法的定义和使用129 3.6.2带参数构造方法的定义和使用131 3.6.3this关键字和构造方法的调用132 3.7静态方法133 3.7.1静态方法的声明和定义134 3.7.2静态方法和实例方法的区别134 3.7.3静态代码块136 3.7.4再论静态成员变量137 3.8main()方法和命令行参数139 3.9结束方法141 3.10本地方法141 3.11本章小结144 第4章继承与多态145 4.1继承的基本原理145 4.2子类对父类的继承146 4.3属性隐藏和方法的覆盖148 4.3.1属性的隐藏148 4.3.2方法的覆盖151 4.4构造方法的继承154 4.5super的使用156 4.5.1用super引用父类的成员156 4.5.2使用super调用父类的构造方法157 4.6继承的内部处理158 4.7多态的基本概念159 4.8重载159 4.8.1普通方法的重载160 4.8.2构造方法的重载161 4.8.3重载的解析163 4.8.4重载与覆盖的区别165 4.9运行时多态165 4.9.1实例方法的运行时多态165 4.9.2成员变量运行时的表现167 4.9.3静态方法运行时

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值