Java网络编程

目录

基于TCP和UDP协议的通信

InetAddress

基于TCP协议的通信,一次请求的对接

基于TCP协议的通信,实现一个聊天室

基于UDP协议的通信,简陋地模拟游戏关闭服务通知场景


基于TCP和UDP协议的通信

基于TCP/IP协议的通信

  1. TCP/IP协议会在通信两端建立连接(虚拟链路),用于发送和接收数据;
  2. TCP/IP协议是一种可靠的网络协议,它通过重发机制来保证这种可靠性;

通信的实现

  1. Serversocket用于监听来自客户端的连接,当没有连接时它处于阻塞状态;
  2. 客户端使用Socket连接到指定的服务器。

基于UDP协议的通信

  1. UDP协议不会在通信两端建立连接(虚拟链路),而是直接发送数据;
  2. UDP协议是一种不可靠的网络协议,但是这种协议的通信效率非常高;

通信的实现

  1. Datagramsocket用于两端的通信,它不负责维护状态、不产生IO流,仅仅是发送或接收数据报;
  2. DatagramPacket代表数据报。

Java使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信

InetAddress

public static  void main(String[] args) throws IOException {
        InetAddress baidu = InetAddress.getByName("www.baidu.com"); //通过域名创建InetAddress对象
        System.out.println(baidu.getHostAddress());//获取主机地址
        System.out.println(baidu.isReachable(2000));//判断目标地址是否可达
        InetAddress local = InetAddress.getByAddress(new byte[]{127, 0,  0, 1});//通过ip地址创建InetAddress对象
        System.out.println(local.getHostName());
        System.out.println(local.isReachable(2000));
}

基于TCP协议的通信,一次请求的对接

服务端程序

public class TcpServer {
    public static  void  main(String[] args){
        try{
            //服务端的端口需要指定,但客户端的端口是随机分配的
            ServerSocket serverSocket = new ServerSocket(9000);
            //这里是个阻塞的逻辑,可以观察到当运行程序的时候,即使是死循环,控制台没有输出任何信息
            while(true){
                Socket socket = serverSocket.accept();//返回的是客户端访问的一些信息,如果没有用户就会阻塞在这里
                System.out.println("请求:" + socket.toString());
                //往客户端输出数据(站在服务端的角度)
                PrintStream ps = new PrintStream(socket.getOutputStream());
                ps.println("Welcome " + socket.getInetAddress().getHostAddress());
                //通信结束需要关闭socket,而且内部的输入输出流也会自动关闭,不用我们手动关闭
                socket.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

客户端程序

public class TcpClient {
    public static  void main(String[] args){
        try{
            Socket socket = new Socket("127.0.0.1", 9000);
            //读取服务端给我们发送过来的数据(输入流)
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = br.readLine();
            System.out.println(line);
            socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

基于TCP协议的通信,实现一个聊天室

A给服务端发送一个消息,服务端再把这个消息发送给所有的用户,所以,服务端需要能够支持多个客户端并发访问多线程

客户端也需要并发(也要基于多线程),因为可以一边输入消息,一边看到别人给我们发过来的消息。

服务端程序

public class TcpServer {
public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
//记录每一个客户端(包装成线程安全的集合)
    public static List<Socket> socketList = Collections.synchronizedList(new ArrayList<>());
    public static  void  main(String[] args){
        try{
            ServerSocket serverSocket = new ServerSocket(9000);
            while(true){
                Socket socket = serverSocket.accept();
                socketList.add(socket);
                //每个人给我发过来的消息我都需要创建一个线程去完成处理,作为一个参数传递进去
                threadPool.submit(new ThreadTask(socket));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
   static class ThreadTask implements  Runnable{
        private Socket socket;
        private BufferedReader reader;//主要操作是从socket里面读到一条数据,所以需要使用到BufferedReader类
       public ThreadTask(Socket socket) {
           this.socket = socket;
           try {
               reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
           }catch (Exception e){
               e.printStackTrace();
           }
       }

       @Override
        public void run() {
           try{
               String line = reader.readLine();
               if(line != null){
                   for(Socket client : TcpServer.socketList){
                       String from = client.getInetAddress().getHostAddress() + ":" + socket.getPort();
                       String content = from + "说:" + line;//这是需要发送给每个客户端的内容
                       //注意:这里不能关闭流(都是长连接的,因为可以无限地交流下去)
                       //需要创建输出流,往输出流中写入内容
                       new PrintStream(client.getOutputStream()).println(content);
                   }
               }
           }catch (Exception e){
               e.printStackTrace();
           }
        }
    }
}

客户端程序

public class TcpClient {
    public static ExecutorService threadPool = Executors.newFixedThreadPool(3);
    public static  void main(String[] args){
        try{
            //连上服务器以后一边需要从服务器读消息,一边需要向服务器写消息,需要两个线程
            Socket socket = new Socket("127.0.0.1", 9000);
            threadPool.submit(new ReadTask(socket));
            threadPool.submit(new WriteTask(socket));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static class ReadTask implements Runnable{
        private Socket socket;
        private BufferedReader reader;
        public ReadTask(Socket socket) {
            this.socket = socket;
            try{
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            }catch (Exception e){
                e.printStackTrace();
            } 
        }
        //从服务器端读取任何人发送过来的消息
        @Override
        public void run() {
            try{
                String line;
                while((line = reader.readLine()) != null){
                    System.out.println(line);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static class WriteTask implements Runnable{
        private Socket socket;
        private PrintStream writer;
        public WriteTask(Socket socket) {
            this.socket = socket;
            try{
                writer = new PrintStream(socket.getOutputStream());
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            Scanner scanner  = new Scanner(System.in);
            String line;
            while((line = scanner.nextLine()) != null){
                writer.println(line);
            }
        }
    }
}

基于UDP协议的通信,简陋地模拟游戏关闭服务通知场景

底层不是通过数据流完成通信的,而是通过数据报完成数据通信的

服务端程序

public class UdpServer {
    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
    public static List<InetSocketAddress> addressList = new ArrayList<>(); //只需要存储IP的端口,UDP是面向报文流的,只要能代表唯一的客户端即可
    public static void main(String[] args) {
        try{
           //创建,随时准备接收
            DatagramSocket socket = new DatagramSocket(9001);
            //随时通知
            threadPool.submit(new SendTask(socket));
            //接受注册[接受数据,把数据放在buffer里面]
            byte[] buffer = new byte[1024];
            //创建数据报,接收的数据放到buffer里面
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            while (true){//因为接收是不停地接收
                //receive会把socket中的数据写到packet中
                socket.receive(packet);//packet中就会有内容
                addressList.add((InetSocketAddress) packet.getSocketAddress());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
//创建一个超级管理员,可以随时发送通知
class SendTask implements Runnable{
    private DatagramSocket socket;

    public SendTask(DatagramSocket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try{
           //管理员敲击几个字发送给每个注册的用户
            Scanner scanner = new Scanner(System.in);
            String line;
            while((line = scanner.nextLine()) != null){
                for(InetSocketAddress isa : UdpServer.addressList){
                    byte[] buffer = line.getBytes();//把字符串的转换为字节数组即可
                    DatagramPacket packet = new DatagramPacket(
                            buffer, buffer.length, isa.getAddress(), isa.getPort());
                    socket.send(packet);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

客户端程序

public class UdpClient {
    public static ExecutorService threadPool = Executors.newFixedThreadPool(3);
    public static  void main(String[] args){
        try{
            DatagramSocket socket = new DatagramSocket();//client端口是随机的
            //注册
            DatagramPacket packet = new DatagramPacket(new byte[]{1}, 1, InetAddress.getByName("127.0.0.1"), 9001);
            socket.send(packet);

            //接收
            threadPool.submit(new ReceiveTask(socket));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static class ReceiveTask implements Runnable{
        private DatagramSocket socket;
        public ReceiveTask(DatagramSocket socket) {
            this.socket = socket;
        }     //接收从服务端发送过来的数据
        @Override
        public void run() {
            try{
                byte[] buffer = new byte[1024];
                DatagramPacket  packet = new DatagramPacket(buffer, buffer.length);
                while(true){
                    socket.receive(packet);
                    //传递的是接收的有效值(也就是实际的长度)
                    String line = new String(packet.getData(),0, packet.getLength());
                    System.out.println(line);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值