1. 网络编程基础知识
1.1 网络基础知识
0. 网络分类:
- 按规模大小和延伸范围分: 局域网(LAN), 城域网(MAN), 广域网(WAN).
- 按网络的拓扑结构分: 星型网络, 总线网络, 环线网络, 树型网络, 星型环线网络等.
- 按传输介质: 双绞线网, 同轴电缆网, 光纤网, 卫星网等.
1. 计算机网络中实现通信必须有一些约定, 这些约定被称为通信协议. 通信协议负责对传输速率, 传输代码, 代码结构, 传输控制步骤, 出错控制等制定处理标准.
2. 通信协议由三部分组成:
- 语义部分: 用于决定双方对话的类型.
- 语法部分: 决定双方对话的格式.
- 变换规则: 决定应答关系.
3. OSI七层模型:
- Open System Interconnection, OSI, 开放系统互联参考模型.
- OSI把网络分成七层: 物理层, 数据链路层, 网络层, 传输层, 会话层, 表示层, 应用层.
- TCP协议(Transmission Control Protocol), 传输控制协议, 它规定一中可靠地数据信息传递服务. IP协议(Internet Protocol), 互联网协议, 是支持网间互联的数据报协议.
1.2 IP地址和端口号
0. IP地址是一个32位(32bit)的整数, 端口是16位的整数.
1. 端口用于表示数据交给哪个通信程序处理, 所以端口就是应用程序与外界交流的出入口.
2. Java的基本网络支持
Java为网络支持提供了java.net包, 该包下的URL和URLConnection等类提供了一编程方式访问Web服务的功能, 而URLDecoder和URLEncoder提供了普通字符串和application/x-www-form-urlencoded MIME字符串互相转换的静态方法.
2.1 使用InetAddress
0. Java使用InetAddress类代表IP地址, 有Inet4Address, Inet6Address两个子类.
1. InetAddress没有构造器, 而有两个静态方法获取InetAddress实例:
- getByName(String host): 根据主机获取对应的InetAddress对象.
- getByAddress(byte[] addr): 根据原始IP地址获取对应的InetAddress对象.
2. 三个方法获取InetAddress实例对应的IP地址和主机名:
- String getCanonicalHostName(): 获取此IP地址的全限定域名.
- String getHostAddress(): 返回该InetAddress实例对应的IP地址字符串(以字符串形式).
- String getHostName()
2.2 使用URLDecoder和URLEncoder
当URL地址里包含非西欧字符的字符串时, 系统会将这些字符串转换成applicatio/x-www-form-urlencoded MIME字符串. 这类过程使用这两个类:
- URLDecoder类包含一个decode(String s, String enc)静态方法, 将看上去乱码的特殊字符串转成普通字符串. s是要操作的字符串, enc是编码方式(如"GBK").
- URLEncoder类包含一个encode(String s, String enc)静态方法, 把普通字符串转成applicatio/x-www-form-urlencoded MIME字符串.
2.3 使用URL和URLConnection
0. URL(Uniform Resource Locator)对象代表统一资源定位器. 格式: protocol://host:port/resourceName .
1. URL的方法:
- String getFile(): 获得该URL的资源名.
- String getHost().
- String getPath().
- int getPort().
- Strinig getProtocol().
- String getQuery(): 获取该URL的查询字符串部分.
- URLConnection openConnection(): 返回一个URLConnection对象, 代表与URL所引用的远程对象的连接.
- InputStream openStream(): 打开于此URL的连接, 并返回一个用于读取该URL资源的InputStream.
3. 基于TCP协议的网络编程
TCP/IP通信协议在通信的两端各建一个Socket, 从而在通信的两端之间形成网络虚拟链路. Java使用Socket对象代表两端的通信端口, 并通过Socket产生IO流来进行网络通信.
3.1 TCP协议基础
0. IP协议负责将信息从一个主机传送到另一个主机, 消息在传送的过程中被分割成一个个的小包.
1. IP协议不能结局传输过程中可能出现的问题, 用TCP协议来提供可靠并且无差错的通信服务.
2. 两台计算机连接时, TCP协议会让他们建立一个用于发送和接收数据的虚拟链路. TCP协议负责收集这些信息包, 并按次序传送, 接收端收到后再将它们正确还原. TCP保证数据包在传送中准确无误. TCP使用重发机制(发送信息后, 需要受到另一个通信实体的确认信息, 没有收到则重发.).
3.2 使用ServerSocket创建TCP服务器端
0. Java中能接受其他通信实体连接请求的类是ServerSocket, ServerSocket对象用于监听来自客户端的Socket连接(如果没有连接, 将一直处于等待状态).
1. ServerSocket的构造器:
- ServerSocket(int port): 用指定端口port创建一个ServerSocket.
- ServerSocket(int port, int backlog): 增加一个用来改变连接队列长度的参数backlog.
- ServerSocket(int port, int backlog, InetAddress loaclAddr): 在及其存在多个IP地址的情况下, 允许通过localAddr参数指定将ServerSocket绑定到指定的IP地址.
2. ServerSocket使用完毕后, 使用ServerSocket的close()方法关闭.
3. ServerSocket包含一个监听来自客户端连接请求的方法:
- Socket accept(): 如果接收到一个客户端Socket的连接请求, 返回一个与客户端Socket对应的Socket; 否则该方法一直处于等待状态, 线程也被阻塞.
3.3 使用Scocket进行通信
0. java.util.Socket的构造器:
- Socket(InetAddress/String remoteAddress, int port): 创建连接到指定远程主机, 远程端口的Socket, 没有指定本地地址和端口, 默认使用本地主机的默认IP地址和系统动态分配的端口.
示例:
# 执行上面代码是, 改代码将会连接到指定服务器, 让服务器端的ServerSocket的accept()方法向下执行, 与是服务器端和客户端产生了一对互相连接的Socket.Socket s = new Socket("127.0.0.1", 30000);
- Socket(InetAddress/String remoteAddress, int port, InetAddress localAddr, int localPort): 指定了本底地址和端口, 使用与本地主机有多个IP地址的情况.
1. 客户端和服务器端产生对应的Socket后, 就可以通过各自Socket通信了.
2. Socket的两个方法获取输入流和输出流:
- InputStream getInputStream(): 返回该Socket对象对应的输入流, 让程序通过该输入流从Socket中取出数据.
- OutputStream getOutputStream()
3. 例子.
Server端:
import java.net.*;
import java.io.*;
public class Server
{
public static void main(String[] args)
throws IOException
{
ServerSocket ss = new ServerSocket(30000);
while(true)
{
Socket s = ss.accept();
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(" *you get a message from server*" );
ps.close();
s.close();
}
}
}
Client端:
import java.net.*;
import java.io.*;
public class Client
{
public static void main(String[] args)
throws IOException
{
Socket socket = new Socket("127.0.0.1", 30000);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
System.out.println("#FROM SERVER: " + line);
br.close();
socket.close();
}
}
3.4 加入多线程
0. 服务器端应为每个Socket连接启动一个线程.
1. 客户端读取服务器端的数据的线程同样会被阻塞, 所以应该单独启动一个线程负责读取服务器端的数据.
3.5 记录用户信息
* 3.4 和 3.5讲C/S结构聊天室怎么写.
3.6 半关闭的Socket
0. 要表示输出已经结束可以通过关闭输出流来实现, 但是在网络通信中如果关闭输出流, 则对应的Socket也将随之关闭, 这样导致程序无法从该Socket的输入流中读取数据.
1. Socket低通两个瓣关闭的方法, 只关闭Socket的输入流或者输出流, 用以表示输出数据已经发送完成:
- shutdownInput(): 关闭该Socket的输入流, 程序还可以通过该Socket的输出流输出数据.
- shutdownOutput().
如果一个Socket实例先后调用了shutdownInput()和shutdownOutput()方法, 此Socket也没关闭, 只是出于不能读写数据的状态了.
3.7 使用NIO实现非阻塞Socket通信
# 使用NIO的多人聊天室.
3.8 使用Java7的AIO实现非阻塞通信
Java 7的NIO.2提供了异步Channel支持, 基于异步Channel的IO机制叫异步IO(Asynchronous IO, AIO).
# AIO聊天工具.
----------------------------------------
挖坑不填
----------------------------------------