1:TCP 通信
linux 通信
文件描述符是内核提供给用户来安全操作文件的标识。
TCP 服务端:
Socket 类
该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。
构造
public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的 host 是 null ,则相当于指定地址为回送地址。
方法
- public InputStream getInputStream() : 返回此套接字的输入流。
- 如果此 Scoket 具有相关联的通道,则生成的 InputStream 的所有操作也关联该通道。
- 关闭生成的 InputStream 也将关闭相关的 Socket。
- public OutputStream getOutputStream() : 返回此套接字的输出流。
- 如果此 Scoket 具有相关联的通道,则生成的 OutputStream 的所有操作也关联该通道。
- 关闭生成的 OutputStream 也将关闭相关的 Socket。
- public void close() :关闭此套接字。
- 一旦一个 socket 被关闭,它不可再使用。
- 关闭此 socket 也将关闭相关的 InputStream 和 OutputStream 。
- public void shutdownOutput() : 禁用此套接字的输出流。
- 任何先前写出的数据将被发送,随后终止输出流。
步骤:
- 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端 响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
- 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
- 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息 (但不能读取自己放入线路的信息),通过输出流将信息写入线程。
- 关闭 Socket:断开客户端到服务器的连接,释放线路
Linux 的步骤:
第一步:调用 socket()函数创建一个用于通信的套接字。
第二步:通过设置套接字地址结构,说明客户端与之通信的服务器的 IP 地址和端口号。
第三步:调用 connect()函数来建立与服务器的连接。
第四步:调用读写函数发送或者接收数据。
第五步:终止连接。
ServerSocker 类
这个类实现了服务器套接字,该对象等待通过网络的请求。
构造
public ServerSocket(int port) :使用该构造方法在创建 ServerSocket 对象时,就可以将其绑定到一个指定的端口号上,参数 port 就是端口号。
方法
public Socket accept() :侦听并接受连接,返回一个新的 Socket 对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。
步骤:
- 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。
- 调用 该 Socket 类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。
- 关闭 ServerSocket 和 Socket 对象:客户端访问结束,关闭通信套接字。
linux 的步骤:
步骤:
第一步:调用 socket()函数创建一个用于通信的套接字。
第二步:给已经创建的套接字绑定一个端口号,这一般通过设置网络套接口地址和调用 bind()函数来实现。
第三步:调用 listen()函数使套接字成为一个监听套接字。
第四步:调用 accept()函数来接受客户端的连接,这是就可以和客户端通信了。
第五步:处理客户端的连接请求。
第六步:终止连接
NIOSocket
服务端 NIOSocket 的处理过程:
- 创建 ServerSocketChannel 并设置相应的端口号、是否为阻塞模式
- 创建 Selector 并注册到 ServerSocketChannel 上
- 调用 Selector 的 selector 方法等待请求
- Selector 接收到请求后使用 selectdKeys 返回 SelectionKey 集合
- 使用 SelectionKey 获取到 channel、selector 和操作类型并进行具体操作。
代码如下:
public class NIOServer {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//创建ServerSocketChannel,监听8080端口
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(8080));
//设置为非阻塞模式
ssc.configureBlocking(false);
//为ssc注册选择器
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
//创建处理器
Handler handler = new Handler(1024);
while(true){
//等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,如果传入0或者不传入参数则一直阻塞
if(selector.select(3000) == 0){
System.out.println("等待请求超时----");
continue;
}
System.out.println("处理请求----");
//获取处理的SelectionKey
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while(keyIter.hasNext()){
SelectionKey key = keyIter.next();
try{
//接收到连接请求时
if(key.isAcceptable()){
handler.handleAccept(key);
}
//读数据
if(key.isReadable()){
handler.handleRead(key);
}
}catch(IOException ex){
keyIter.remove();
continue;
}
//处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key
keyIter.remove();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static class Handler{
private int bufferSize = 1024;
private String localCharset = "UTF-8";
public Handler(int bufferSize){
this.bufferSize = bufferSize;
}
public void handleAccept(SelectionKey key) throws IOException{
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
sc.configureBlocking(false);
sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
}
public void handleRead(SelectionKey key) throws IOException{
//获取Channel
SocketChannel sc = (SocketChannel) key.channel();
//获取buffer并重置
ByteBuffer buffer = (ByteBuffer)key.attachment();
buffer.clear();
//没有读到内容则关闭
if(sc.read(buffer) == -1)
sc.close();
else{
//将buffer转换为读状态
buffer.flip();
//将buffer中接收到的值按localCharset格式编码后保存到receivedString
String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
System.out.println("received from client:" + receivedString);
//返回数据给客户端
String sendString = "this data is from Server";
buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
sc.write(buffer);
sc.close();
}
}
}
}
客户端代码通普通 Socket 一样,Socket socket = new Socket(“192.168.6.42”,8080);表示与服务器端建立连接,从而执行服务器端的 handleAccept()方法,给 ServerSocketChannel 注册 selector 以及添加 SelectionKey.OP_READ 参数,表示 selector 关心读方法。然后通过 PrintWrite 在客户端将内容发送给服务器端,服务器端执行 handleRead 方法对接收到的内容进行处理,并将结果返回给客户端,客户端通过 BufferedReader 接受数据,最后关闭连接。
2:UDP 通信
类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。
流 程:
- DatagramSocket 与 DatagramPacket 2.
- 建立发送端,接收端 3.
- 建立数据包 4.
- 调用 Socket 的发送、接收方法 5.
- 关闭 Socket
3:URL 编程
针对 HTTP 协议的 URLConnection 类
提供了最高级网络应用。URL 的网络资源的位置来同一表示 Internet 上各种网络资源。通过 URL 对象可以创建当前应用程序和 URL 表示的网络资源之 间的连接,这样当前程序就可以读取网络资源数据,或者把自己的数据传送到网络上去。