• java web----TCP/DUP 通信


    下面的案例是C/S结构,既编写客户端有编写服务端而且没有用到http协议

    对于B/S结构,我们只需要编写服务器,不需要写客户端。

    服务端和单客户端通信

    注意事项:如果服务端或者客户端采用read() 一个字节这种读取数据,只要另一方没有关闭连接,read是永远读取不到-1,会陷入死循环中;

    解决方法:加上一个判断,程序员自己跳出循环,比如在while循环中,加上

    if(strbuilder.indexOf("
    ") > 0){//存在消息结束标志
        break;
    }

    服务端代码

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server {
        public static void main(String[] args) {
            try {
                ServerSocket server = new ServerSocket(8080);
                Socket socket = server.accept();
                System.out.println("客户端连接成功:"+server.getInetAddress().getHostAddress());
    
                BufferedReader bufRead = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String s = bufRead.readLine();
                System.out.println("message="+s);
    
    
                BufferedWriter bufwrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bufwrite.write("你好我是服务端
    ");
                bufwrite.flush();
    
                bufwrite.close();
                bufRead.close();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    } 

    客户端代码

    import java.io.*;
    import java.net.Socket;
    
    public class client {
        public static void main(String[] args) {
            try {
                Socket socket = new Socket("127.0.0.1",8080);
                BufferedWriter bufWrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                //如果服务器使用readline来读取数据,那么发送的数据后面必须加上
    ;
                bufWrite.write("你好我是客户端
    ");
                bufWrite.flush();
    
    
                //PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
                //ps.println("dddd");
                //ps.flush();
    
                BufferedReader bufread = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println(bufread.readLine());
    
                //ps.close();
                bufWrite.close();
                bufread.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    服务器和多客户端通信

     即采用多线程的方式进行处理任务

    服务端

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class Server {
        public static void main(String[] args) {
            try {
                ExecutorService es = Executors.newFixedThreadPool(4);
                ServerSocket server = new ServerSocket(8080);
                while (true){
                    Socket socket = server.accept();
                    System.out.println("有客户端连接");
                    es.execute(new ServerHandle(socket));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    class ServerHandle implements Runnable{
        private Socket socket;
        public ServerHandle(Socket socker){
            this.socket = socker;
        }
        @Override
        public void run() {
            BufferedReader bufRead = null;
            try {
                bufRead = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
                char[] chars = new char[1024];
                StringBuilder strbuilder = new StringBuilder();
                int len=-1;
                while ((len=bufRead.read(chars))!=-1){
                    strbuilder.append(new String(chars),0,len);
                    if(strbuilder.indexOf("
    ") > 0){//存在消息结束标志
                        break;
                    }
                }
                System.out.println("message="+ strbuilder);
                BufferedWriter bufwrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bufwrite.write("已经收到你的信息:"+strbuilder+"
    ");
                bufwrite.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    客户端

    import java.io.*;
    import java.net.Socket;
    import java.util.Scanner;
    
    public class client {
        public static void main(String[] args) {
            try {
                Socket socket = new Socket("127.0.0.1",8080);
                BufferedWriter bufWrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                //如果服务器使用readline来读取数据,那么发送的数据后面必须加上
    ;
                Scanner input = new Scanner(System.in);
                System.out.println("输入一个发送的信息");
                String x = input.next();
                bufWrite.write(x+"
    ");
                bufWrite.flush();
    
                BufferedReader bufread = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println(bufread.readLine());
    
                bufWrite.close();
                bufread.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    多客户端之间的通信

    Server端

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Vector;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class Server {
        public static void main(String[] args) {
            //保存所有的处理 用户请求连接的 线程
            Vector<UserRequestHandle> vector = new Vector<>();
            ExecutorService es =  Executors.newFixedThreadPool(4);
            try {
                ServerSocket server  =  new ServerSocket(8080);
                System.out.println("服务器已经启动.......");
                while (true){
                    Socket socket = server.accept();
                    UserRequestHandle user = new UserRequestHandle(socket,vector);
                    vector.add(user);
                    es.execute(user);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    class UserRequestHandle implements Runnable{
        private String name;//客户端的名字(唯一),可以绑定用户对象(唯一);
        private ObjectInputStream ois;
        private ObjectOutputStream oos;
        private Socket socket;
        private Boolean flag=true;
        private Vector<UserRequestHandle> verctor;
        public UserRequestHandle(Socket socket,Vector<UserRequestHandle> verctor){
            this.socket = socket;
            this.verctor = verctor;
        }
        @Override
        public void run() {
            try {
                ois = new ObjectInputStream(socket.getInputStream());
                oos = new ObjectOutputStream(socket.getOutputStream());
                while (flag){
                    Message message = (Message) ois.readObject();
                    int mes = message.getType();
                    switch (mes){
                        case MessageType.type_login:{
                            name = message.getFrom(); //表示给当前的线程取一个名字;
                            message.setMessage("欢迎登录"+message.getFrom());
                            oos.writeObject(message);
                            break;
                        }
                        case MessageType.type_send:{
                            String to_user = message.getTo();
                            String to_user_message = message.getMessage();
                            for (int i = 0; i < verctor.size(); i++) {
                                if (verctor.get(i).name==null|to_user==null){
                                    continue;
                                }
                                if (verctor.get(i).name.equals(to_user)&&!to_user.equals(this.name)){
                                    System.out.println("消息已经正在发送给对方.....");
                                    message.setFrom(name);
                                    message.setMessage(to_user_message);
                                    verctor.get(i).oos.writeObject(message);
                                    break;
                                }
                            }
                        }
    
                    }
                }
                ois.close();
                oos.close();
            } catch (IOException|ClassNotFoundException e) {
                e.printStackTrace();
                return;
            }catch (Exception e){
            }
        }
    }

     客户端

    import java.io.*;
    import java.net.Socket;
    import java.util.Scanner;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class client {
        public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            try {
                Socket socket = new Socket("127.0.0.1",8080);
                System.out.println("连接服务器成功......");
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                //第一步先登录;
                System.out.println(MessageType.type_login+","+MessageType.type_send);
                System.out.println("输入用户名");
                String name = input.next();
                oos.writeObject(new Message(name,null,MessageType.type_login,null));
                Message message = (Message) ois.readObject();
                System.out.println(message.getMessage());
                
                //创建一个单线程从socket中循环取出消息(只读)
                ExecutorService receve_message = Executors.newSingleThreadExecutor();
                receve_message.execute(new ReceveMessage(ois));
    
                //不断给服务发送消息(只写)
                while (true){
                    System.out.println("输入要发送消息的用户名");
                    String to_user = input.next();
                    System.out.println("输入消息");
                    String to_user_message = input.next();
                    oos.writeObject(new Message(name,to_user,MessageType.type_send,to_user_message));
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    
    class ReceveMessage implements Runnable{
        private ObjectInputStream ois;
        public ReceveMessage(ObjectInputStream ois){
            this.ois = ois;
        }
        @Override
        public void run() {
            try {
                while (true){
                    Message message = (Message) this.ois.readObject();
                    System.out.println("["+message.getFrom()+"]"+":"+message.getMessage());
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    message信息对象

    import java.io.Serializable;
    
    
    public class Message implements Serializable {
        private String from;  //发送消息的人(以后可以用ip来处理)
        private String to;    //发送消息给谁(以后可以用ip来处理)
        private int type; //int type  消息的类型(是登录还是进行消息的发送)
        private String message;//消息的内容
        public Message(String from, String to, int type, String message) {
            this.from = from;
            this.to = to;
            this.type = type;
            this.message = message;
        }
        public String getFrom() {
            return from;
        }
        public String getTo() {
            return to;
        }
        public int getType() {
            return type;
        }
        public String getMessage() {
            return message;
        }
        public void setFrom(String from) {
            this.from = from;
        }
        public void setTo(String to) {
            this.to = to;
        }
        public void setMessage(String message) {
            this.message = message;
        }
    }
    

    MessageType表示配置文件

    public class MessageType {
        public static final int type_login = 1;//消系中有type_login表示需要登录
        public static final int type_send = 2; //消息中有type_send表示该消息为发送
    }

    TCP聊天室原理

    服务器用于转发消息

    客户端和服务器建立一个socket连接

    客户端将socker交给两个线程处理,一个线程(可以使用主线程)用来接收服务端的数据,一个线程用来发送数据

    服务端接收到一个连接请求,就开启1个线程来处理请求,并将socker添加到列表中这个列表可以被每一个线程共享,当线程接收到数据后,就遍历列表,对每一个socker进行发送数据(可以选择不给自己发送数据,!=this)。

    TCP私聊

    我们之前已经封装好了一个socker列表,当某一个客户端发送数据@xx:你好,我们可以截取xx,在发送数据的时候如果数据中有@符号,就给某一个socker发送数据。

    注意我们可以封装一个socker连接对象,里面传入socker,name,并且封装send(),recive()方法,将这个封装对象add到列表中。

    UDP服务端和客户端通信

    UDP没有严格意义上的服务端

    服务端

    public class Server {
        public static void main(String[] args) throws IOException {
            //UDP协议要求包小于64K,我们用500个字节数组来接受数据,如果发送的数据大于500个字节,超过500字节的数据接受不到
            byte[] bs = new byte[500];
            //准备容器,用这个容器来接受客户端发送的数据
            DatagramPacket p1 = new DatagramPacket(bs, bs.length);
            //创建数据报套接字
            DatagramSocket socket_B = new DatagramSocket(10010);
            //接收数据报包
            socket_B.receive(p1);
            System.out.println(new String(bs, 0, p1.getLength()));
    
            byte[] send_msg = "我是服务端,我已经收到你的消息".getBytes();
            InetAddress desIp = p1.getAddress(); //获取对方的ip
            int dedport = p1.getPort();
            //数据包中包括数据,数据长度,对方的ip和绑定的端口
            DatagramPacket p = new DatagramPacket(send_msg, send_msg.length, desIp, dedport);
            socket_B.send(p);
            socket_B.close();
        }
    }

    客户端

    public class Client {
        public static void main(String[] args) throws IOException {
            byte[] send_bs = "我是客户端,我给你发送了一些数据".getBytes();//要发的信息内容
            //创建数据报,里面包括  数据和数据长度  对方的ip地址 和 对方的端口,
            DatagramPacket p1 = new DatagramPacket(send_bs, send_bs.length, InetAddress.getByName("127.0.0.1"),10010);
            //创建数据报套接字,绑定端口
            DatagramSocket socket = new DatagramSocket(8080);
            socket.send(p1);
    
            //用数组接收数据报包
            byte[] rece_msg = new byte[500];
            DatagramPacket p = new DatagramPacket(rece_msg, rece_msg.length);
            socket.receive(p);//数据量如果多,可以使用while循环
            System.out.println(new String(rece_msg, 0, p.getLength()));
            //关闭套接字
            socket.close();
        }
    }

    udp实现双向发送数据

    服务端(客户端)和客户端都必须开2个线程,一个线程用于发送数据,System.in堵塞该线程,一个线程等待对方发送数据,receive()堵塞该线程

      

    一个简单的B/S架构服务器

    http协议(应用层传输协议)

      首先tcp/udp协议,只能保证数据的发送,服务器(客户端)通过tcp可以获取客户端(服务器)发送的消息,但是如果来解析这些数据呢,这就需要一个标准的协议,并且全世界都必须遵循。这个协议(http),规定了服务器和客户端发送数据的格式。接受方有安装标准协议来解析这些数据,获得有用的信息。

      现在浏览器会安装http协议通过tcp发送一段特殊的格式的数据,你的服务器就需要按照http协议的格式来解析这些数据,而服务器发送给浏览器的数据,浏览器只会按照http标准格式数据解析。所以我们发送的数据必须按照http格式要求写。

      当然如果你可以单独开发一款浏览器,这个浏览器访问你的服务器,你想怎么定协议就怎么定协议。只要你的服务器和浏览器可以解析正确的数据就行,你也可以将你解析数据的方式,和方式数据的格式定义你的协议。这就是应用层协议。

    请求协议

    请求行:方法(GET/POST)、URI、协议/版本
    请求头:Request Header
    请求正文
    1、请求行
      GET /index.htm1?name=xx  HTTP/1.1
    2、请求体
      Accept:text/html,application/xhtml+xml,*/*
      Accept-Language:zh-CN
      User-Agent:Mozilla/5.0(compatible;MSIE 9.0;W indows NT 6.1;Trident/5.0)
      Accept-Encoding:ggip,deflate
      Host:localhost
      Connection:Keep-Alive
    3、请求正文

    响应协议

    状态行:协议/版本、状态码,转态描述
    响应头(Response Header)
    响应正文
    1、状态行
           HTTP/1.0 2000K
    2、请求头:
      Date:Mon,31Dec209904:25:57GMT
      Server:shsxt Server/0.0.1;charset=GBK
      Content-type:text/html
      Content-length:397254263
    请求正文(注意与请求头之间有个空行)
    
      xxxx
    

      

    服务器

    public class Server {
        public static void main(String[] args) {
            try {
                ServerSocket server = new ServerSocket(8080);
                Socket socket = server.accept();
                System.out.println("客户端连接成功:"+server.getInetAddress().getHostAddress());
    
                BufferedReader bufRead = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String s = bufRead.readLine();
                System.out.println("message="+s);
    
                BufferedWriter bufwrite = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bufwrite.write("HTTP 1.1
    
    <h1>xx</h1>");
                bufwrite.flush();
    
                bufwrite.close();
                bufRead.close();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    Pyhon基础过滤字符串中的字母数字特殊符号
    [编程题] 斐波那契数列
    左旋转字符串(Java)-循环Index方式
    [编程题]字符流中第一个不重复的字符
    6525. 【2020.4.1模拟】Valleys
    6515. 【GDOI2020模拟03.28】数一数(one)
    6516. 【GDOI2020模拟03.28】数二数(two)
    6508. 【GDOI2020模拟03.11】我的朋友们
    6494. 【GDOI2020模拟03.08】勘探
    6491. 【GDOI2020模拟03.04】铺路
  • 原文地址:https://www.cnblogs.com/yanxiaoge/p/10740302.html
Copyright © 2020-2023  润新知