zoukankan      html  css  js  c++  java
  • Java-socket编程(建立连接)

    socket编程是以IO为理论基础的,理论学得差不多也很难实现编程,毕竟里面的类和方法平时都不怎么用,难得尝试编了个程,记录一下。

    1.几个概念

    Channel:管道,连通客户端和服务端传输数据;

    Buffer:缓冲区,通过管道传输数据必须经过的地方;

    Selector:选择器,单线程可以通过选择器处理多个管道;本文没有使用;

    2.案例功能

    启动服务端,再启动客户端与服务端连接,在客户端的控制台输入命令获取服务端的效果。本样例只处理了“time”命令,获取服务端的当前时间,其他命令都返回“非指定命令,无返回值”。详看代码注释。

    3.服务端代码

     1 import java.net.InetSocketAddress;
     2 import java.nio.ByteBuffer;
     3 import java.nio.channels.ServerSocketChannel;
     4 import java.nio.channels.SocketChannel;
     5 import java.nio.charset.StandardCharsets;
     6 import java.util.Date;
     7 import java.util.LinkedList;
     8 
     9 public class NIOService {
    10     static int PORT = 9011;
    11     public static void main(String[] args) throws Exception{
    12         //存储客户端连接
    13         LinkedList<SocketChannel> clients = new LinkedList<>();
    14         //1.服务端开启监听:接受客户端
    15         ServerSocketChannel ss = ServerSocketChannel.open();
    16         ss.bind(new InetSocketAddress(PORT));
    17         //2.只接受客户端,不阻塞
    18         ss.configureBlocking(false);
    19 
    20         while (true) {
    21             // 接受客户端的连接
    22             // client在Java层面是一个对象,在内核层面是一个fd
    23             SocketChannel client = ss.accept();
    24             if (client == null) {
    25                 //while循环进来没有 连到客户端就不管
    26             } else {
    27                 //和client传输数据使用的socket->fd
    28                 client.configureBlocking(false);
    29                 //获取客户端的端口号
    30                 int port = client.socket().getPort();
    31                 System.out.println("接收到客户端的连接,client port: " + port);
    32                 //将客户端添加到列表里
    33                 clients.add(client);
    34             }
    35             //可以在堆里,堆外,相关内容,可以看看JVM直接内存
    36             ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
    37 
    38             //遍历已经链接进来的客户端 的管道channel里有没有数据
    39             for (SocketChannel c : clients) {
    40                 //每循环一次都是一次系统调用,都是一次用户内核态的切换
    41                 int num = c.read(buffer);
    42                 if (num > 0) {
    43                     buffer.flip();
    44                     byte[] bytes = new byte[buffer.limit()];
    45                     buffer.get(bytes);
    46                     String s = new String(bytes);
    47                     System.out.println("端口为"+c.socket().getPort() + "的客户端发来命令:" +s);
    48                     String res = "";
    49                     ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4096);
    50                     if("time".equals(s)){
    51                         //获取时间
    52                         long l = System.currentTimeMillis();
    53                         res = "time: "+new Date(l).toString();
    54                         System.out.println(res);
    55                     }else{
    56                         res = "非指定命令,无返回值";
    57                     }
    58                     byteBuffer.put(res.getBytes(StandardCharsets.UTF_8));
    59                     byteBuffer.flip();
    60                     c.write(byteBuffer);
    61                 }
    62                 buffer.clear();
    63             }
    64         }
    65     }
    66 }

     4.客户端代码

     1 import java.io.*;
     2 import java.net.Socket;
     3 import java.nio.channels.ServerSocketChannel;
     4 import java.nio.channels.SocketChannel;
     5 import java.util.Scanner;
     6 
     7 public class Client {
     8     public static void main(String[] args) {
     9         try {
    10             //建立一个客户端连到9010的服务端
    11             Socket client = new Socket("127.0.0.1",9011);
    12             //设置发送命令的长度
    13             client.setSendBufferSize(20);
    14             /**
    15              * 关闭Nagle算法:该算法是将多个命令打包一起发送给服务端,避免网络拥挤。
    16              * 但是现在网络宽松,随便发也没事。所以关闭。
    17              */
    18             client.setTcpNoDelay(false);
    19 
    20             OutputStream out = client.getOutputStream();
    21             InputStream input = client.getInputStream();
    22             InputStream in = System.in;
    23             BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    24             Scanner scan = new Scanner(System.in);
    25             while(true){
    26                 String line = scan.nextLine();
    27                 //String line = reader.readLine();
    28                 if(line != null ){
    29                     //将输入的命令用字节数组存起来,通过客户端client的输出流发送给服务端
    30                     byte[] bb = line.getBytes();
    31                     out.write(bb);
    32                 }
    33                 byte b[] = new byte[1024];
    34                 /**
    35                  从输入流里读 东西 到 b数组,如果没有东西,就会一直读,阻塞。
    36                  len获取当前输入流里的内容长度,英文占1个长度,中文占3个长度
    37                  */
    38                 int len = input.read(b);
    39                 System.out.println(new String(b));
    40             }
    41         } catch (IOException e) {
    42             e.printStackTrace();
    43         }
    44     }
    45 
    46 }
  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/14516451.html
Copyright © 2011-2022 走看看