1:TCP 通信

linux 通信

七、网络编程 - 图1

文件描述符是内核提供给用户来安全操作文件的标识。
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 的处理过程:

  1. 创建 ServerSocketChannel 并设置相应的端口号、是否为阻塞模式
  2. 创建 Selector 并注册到 ServerSocketChannel 上
  3. 调用 Selector 的 selector 方法等待请求
  4. Selector 接收到请求后使用 selectdKeys 返回 SelectionKey 集合
  5. 使用 SelectionKey 获取到 channel、selector 和操作类型并进行具体操作。

代码如下:

  1. public class NIOServer {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub
  4. try {
  5. //创建ServerSocketChannel,监听8080端口
  6. ServerSocketChannel ssc = ServerSocketChannel.open();
  7. ssc.socket().bind(new InetSocketAddress(8080));
  8. //设置为非阻塞模式
  9. ssc.configureBlocking(false);
  10. //为ssc注册选择器
  11. Selector selector = Selector.open();
  12. ssc.register(selector, SelectionKey.OP_ACCEPT);
  13. //创建处理器
  14. Handler handler = new Handler(1024);
  15. while(true){
  16. //等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,如果传入0或者不传入参数则一直阻塞
  17. if(selector.select(3000) == 0){
  18. System.out.println("等待请求超时----");
  19. continue;
  20. }
  21. System.out.println("处理请求----");
  22. //获取处理的SelectionKey
  23. Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
  24. while(keyIter.hasNext()){
  25. SelectionKey key = keyIter.next();
  26. try{
  27. //接收到连接请求时
  28. if(key.isAcceptable()){
  29. handler.handleAccept(key);
  30. }
  31. //读数据
  32. if(key.isReadable()){
  33. handler.handleRead(key);
  34. }
  35. }catch(IOException ex){
  36. keyIter.remove();
  37. continue;
  38. }
  39. //处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key
  40. keyIter.remove();
  41. }
  42. }
  43. } catch (IOException e) {
  44. // TODO Auto-generated catch block
  45. e.printStackTrace();
  46. }
  47. }
  48. private static class Handler{
  49. private int bufferSize = 1024;
  50. private String localCharset = "UTF-8";
  51. public Handler(int bufferSize){
  52. this.bufferSize = bufferSize;
  53. }
  54. public void handleAccept(SelectionKey key) throws IOException{
  55. SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
  56. sc.configureBlocking(false);
  57. sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
  58. }
  59. public void handleRead(SelectionKey key) throws IOException{
  60. //获取Channel
  61. SocketChannel sc = (SocketChannel) key.channel();
  62. //获取buffer并重置
  63. ByteBuffer buffer = (ByteBuffer)key.attachment();
  64. buffer.clear();
  65. //没有读到内容则关闭
  66. if(sc.read(buffer) == -1)
  67. sc.close();
  68. else{
  69. //将buffer转换为读状态
  70. buffer.flip();
  71. //将buffer中接收到的值按localCharset格式编码后保存到receivedString
  72. String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
  73. System.out.println("received from client:" + receivedString);
  74. //返回数据给客户端
  75. String sendString = "this data is from Server";
  76. buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
  77. sc.write(buffer);
  78. sc.close();
  79. }
  80. }
  81. }
  82. }

客户端代码通普通 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 表示的网络资源之 间的连接,这样当前程序就可以读取网络资源数据,或者把自己的数据传送到网络上去。

转载 https://www.yuque.com/jykss/jykss/zezf4y#WDe4S