Java网络编程

1.基本的通信架构

通信架构分为两种:CS架构(客户端/服务器),BS架构(浏览器/服务器)
cs架构:

  • 客户端、服务端需要程序员开发
  • 需要用户安装客户端

bs架构:

  • 不需要安装客户端,通过浏览器就能访问
  • 程序员只需开发服务端

2.网络通信三要素

1.ip,设备的唯一标识
2.端口号,程序的id标识
3.协议,连接和数据传输的规则

2.1 IP地址对象–InetAddress

Java网络编程_第1张图片

2.2 端口号

端口分类
Java网络编程_第2张图片

2.3 协议

Java网络编程_第3张图片
UDP协议

  • 无连接,不可靠通信
  • 事先不建立连接,数据按照包发,一包数据包含:自己的IP,程序端口,目的地IP,程序端口和数据(限制在64KB内)等
  • 发送消息的时候不管对方是否在线,数据是否在中途丢失也不管,接收方接收到消息也不会返回确认,所以是不可靠的
  • 通信的效率较高,传输的速率高,丢了极个别的包影响不大

TCP协议

  • 面向连接,可靠通信
  • TCP的最终目的:要保证在不可靠的信道上实现可靠传输
  • TCP主要有三个步骤实现可靠传输:三次握手连接,传输数据进行确认,四次挥手断开连接

可靠连接:确定通信双方,收发消息都是正常无问题的(全双工通信)

三次握手
Java网络编程_第4张图片

四次挥手断开连接
Java网络编程_第5张图片

3.UDP通信

Java网络编程_第6张图片

//
1.将传输的字符放入字节数组(getbytes方法,将字符串转为字节)
2.传入的字节长度
3.接收端的ip地址
4.接收端的端口号
public DatagramPacket(byte[] buf,int length,InetAddress address, int port)

消息通信,一发一收实现步骤
客户端

  • 1.创建客户端对象DatagramSocket对象
  • 2.创建DatagramPacket对象封装需要发送的数据(数据包对象)
  • 3.使用DatagramSocket对象的send方法,传入DatagramPacket对象
  • 4.关闭释放资源,close

服务端

  • 1.创建DatagramSocket对象并指定端口(服务端对象)
  • 2.创建DatagramPacket对象接收数据(数据包对象)
  • 3.使用DatagramSocket对象的receive方法,传入DatagramPacket对象
  • 4.关闭,释放资源。close()

消息通信,多发多收实现步骤

//服务端
public class UdpSocketServer {
    public static void main(String[] args) throws IOException {

        /**
         * UDP不可靠通信,服务器
         */
        DatagramSocket datagramSocket = new DatagramSocket(9000);//申明一个服务器对象
        byte[]bytes=new byte[1024*64];
        DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length);//申明一个容器用于接收传输过来的数据
        while(true)
        {
            datagramSocket.receive(datagramPacket);//服务器对象接收容器的类容
            String str=new String(bytes,0,datagramPacket.getLength());//将字节数组转换成字符串
            System.out.println(str);
        }

    }

}
//客户端
public class UdpSocketConsumer {
    public static void main(String[] args) throws Exception {
        Scanner scanner=new Scanner(System.in);
        while (true)
        {
            System.out.println("开始输入吧!");
            String str = scanner.nextLine();//将传输的数据转换成字节数组
            if (str.equals("exit"))
            {
                break;
            }
            byte[] bytes = str.getBytes();
            DatagramSocket datagramSocket=new DatagramSocket();//申明一个客户端对象
            DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),9000);//用于存储传输数据,长度,ip,端口
            datagramSocket.send(datagramPacket);//发送消息
        }
    }
}

4.TCP通信

特点:面向连接,可靠通信

TCP通信的步骤
服务端

  • 创建ServerSocket对象,并填写服务端端口
  • 调用ServerSocket对象的accept方法,等待客户端的连接,连接上后,返回一个Socket管道对象
  • 通过得到的Socket对象调用getInputStream方法得到字节输入流,完成数据的接收
  • 关闭释放资源,关闭socket连接
    Java网络编程_第7张图片
    Java网络编程_第8张图片

客户端

  • 创建客户端对象
  • 通过客户端对象调用字节输出流
  • 把低级的字节输出流包装成数据输出流
  • 用高级输出流对象,调用writeUTF()进行输出
  • 关闭流,关闭客户端通信
    Java网络编程_第9张图片
    当客户端建立连接后,后续又关闭连接,需要对服务端进行异常处理,否则服务端一直监听离线的客户端,会报错
    Java网络编程_第10张图片

4.1 TCP实现多发多收

必须将接收到的socket对象交给多个线程管理

聊天室多人通信—cs架构

//客户端,负责向服务器发送消息,服务器转发给其他线程
public class TCPSocketConsumer {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 8999);
        new TCPSocketConsumerThead(socket).start();
        OutputStream outputStream = socket.getOutputStream();
        DataOutputStream dos = new DataOutputStream(outputStream);
        Scanner sc=new Scanner(System.in);
        System.out.println("服务已经启动,开始聊天");
        while (true)
        {
            String line = sc.nextLine();
            if (line.equals("exit"))
            {
                socket.close();
                outputStream.close();
                break;
            }
            dos.writeUTF(line);
        }
    }
}
//客户端线程,负责接收服务端的消息,看到关于自己的线程信息
public class TCPSocketConsumerThead extends Thread{
  private Socket socket;
   public TCPSocketConsumerThead(Socket socket)
   {
       this.socket=socket;
   }
    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();
            DataInputStream dataInputStream = new DataInputStream(inputStream);
            while(true)
            {
                try {

                    String s = dataInputStream.readUTF();
                    System.out.println(s);
                } catch (Exception e) {

                }

            }
        } catch (IOException e) {
            System.out.println("自己下线了");
        }

    }
}
//服务端,负责接收客户端的消息
public class TCPSocketServer {
    public static List<Socket> sockets=new ArrayList<>();
    public static void main(String[] args) throws Exception {

        System.out.println("------服务端启动-----");
        ServerSocket serverSocket = new ServerSocket(8999);
        while (true)
        {
            Socket accept = serverSocket.accept();
            sockets.add(accept);
            System.out.println(accept.getInetAddress()+"已经上线");
            TcpSocketServerThead thead=new TcpSocketServerThead(accept);
            thead.start();
        }
    }

}
//服务端线程,负责将服务端接收到的信息传递给其他客户端线程
public class TcpSocketServerThead extends Thread{
    private Socket socket;

    private DataInputStream dataInputStream;
    public TcpSocketServerThead(Socket socket) {
        this.socket=socket;
    }

    @Override
    public void run()
    {
      while(true){  try
        {
            InputStream inputStream = socket.getInputStream();
            dataInputStream = new DataInputStream(inputStream);
            String s = dataInputStream.readUTF(dataInputStream);
            transAll(s);
            System.out.println(s);

        } catch (Exception e) {
            System.out.println(socket.getInetAddress()+"已经下线");
            TCPSocketServer.sockets.remove(socket);
            try {
                socket.close();
                dataInputStream.close();
                break;
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }}

    public void transAll(String msg) throws IOException
    {
        for(Socket s:TCPSocketServer.sockets)
        {
            OutputStream outputStream = s.getOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF(msg);
            dataOutputStream.flush();
        }
    }
}

BS架构

//之开发服务端,通过网页通信
public class BSSocket {
    public static void main(String[] args) throws IOException {
        System.out.println("------服务端启动-----");
        ServerSocket serverSocket = new ServerSocket(8999);
        while (true)
        {
            Socket accept = serverSocket.accept();
            System.out.println(accept.getInetAddress()+"已经上线");
            BSSocketThread bsSocketThread=new BSSocketThread(accept);
            bsSocketThread.start();
        }
    }
}
//线程
public class BSSocketThread extends Thread{
    private Socket socket;
    public BSSocketThread(Socket socket)
    {
        this.socket=socket;
    }

    @Override
    public void run() {
        try {
            OutputStream outputStream = socket.getOutputStream();
            PrintStream printStream=new PrintStream(outputStream);
            printStream.println("HTTP/1.1 200 OK");
            printStream.println("Content-Type:text/html;charset=UTF-8");
            printStream.println();
            printStream.println("
程序员666
"
); printStream.close(); socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } }

使用BS架构实现通信的话,必须遵守HTTP协议
Java网络编程_第11张图片
如果每次访问都创建一个线程,如果并发很高的话,就可能实现宕机。需要使用线程池

你可能感兴趣的:(socket,java)