Java网络编程---Socket

java网络编程

java中实现网络编程用到的套接字是Socket,在引入Socket的时候先来了解一下网络通信协议。

网络通信协议:

计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。

网络通信协议的分层:

OSI参考模型:

  • 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层

TCP/IP参考模型:

  • 应用层(HTTP、FTP、SMTP、DNS)
  • 传输层(TCP、UDP)
  • 网络层(IP、ARP、ICMP)
  • 链路层(各种网络接口)

TCP

  • 含义:是一种面向连接的、可靠的、基于字节流的运输层通信协议。
  • 特点:
    • 1、面向连接
    • 2、点到点通信
    • 3、高可靠性
    • 4、占用系统资源多、效率低

UDP

  • 含义:一种无连接的传输协议,提供面向事物的简单不可靠信息传送服务。
  • 特点:
    • 1、非面向连接,传输不可靠,数据可能丢失。
    • 2、发送数据时也不管对方是否准备好,接收方也得不到确认。
    • 3、可以广播发送
    • 4、非常简单的协议,开销小。

InetAddress类:

用于封装计算机IP地址,但没有端口。

    //使用getLocalHost方法创建InetAddress对象
    InetAddress addr = InetAddress.getLocalHost();
    System.out.println(addr.getHostAddress());  //返回IP地址
    System.out.println(addr.getHostName());  //输出计算机名

    //根据域名得到InetAddress对象
    addr = InetAddress.getByName(“www.163.com”); 
    System.out.println(addr.getHostAddress());  //返回 163服务器的ip:61.135.253.15
    System.out.println(addr.getHostName());  //输出:www.163.com

    //根据ip得到InetAddress对象
    addr = InetAddress.getByName(“61.135.253.15”); 
    System.out.println(addr.getHostAddress());  //返回 163服务器的ip:61.135.253.15
    System.out.println(addr.getHostName());  //输出ip而不是域名。如果这个IP地 址不存在或DNS服务器不允许进行IP地址和域名的映射,getHostName方法就直接返回这个IP地址。

InetSocketAddress类

用于socket通信,包含端口。

    //包含端口
    InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);
    InetSocketAddress socketAddress2 = new InetSocketAddress(“localhost”,9000);
    System.out.println(socketAddress.getHostName());
    System.out.println(socketAddress2.getAddress());

套接字Socket

在客户/服务器通信模式中,客户端需要主动建立与服务器连接的Socket,服务器端收到客户端的连接请求,也会创建与客户端连接的Socket。Socket可以看做是通信连接两端的收发器,客户端和服务店都通过Socket来收发数据。

Socket通信实现步骤:

  • 1、创建ServerSocket和Socket
  • 2、打开连接Socket的输入/输出流
  • 3、按照协议(TCP/UDP)对Socket进行读写操作
  • 4、关闭输入、输出流,关闭Socket

Server服务端:

  • a、创建ServerSocket对象,同时绑定监听端口
  • b、通过accept()方法监听客户端的请求
  • c、建立连接后,通过输入流读取客户端发送的请求信息
  • d、通过输出流向客户端发送响应信息
  • e、关闭相应资源

TCP编程:

    package com.net.socket;

    import java.io.DataInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;

    /**
    * socket服务端(接受数据)
    * 
    * @author admin
    *
    */
    public class ServiceSocket implements Runnable {
        Thread thread;
    public ServiceSocket() {
        thread = new Thread(this);
        thread.start();
        }
        @Override
        public void run() {
            try {
            // TODO Auto-generated method stub
            System.out.println("服务器已经启动");
            // 1.创建ServerSocket对象
                ServerSocket server = new ServerSocket(8888);
                // 2.通过accept();方法,开启端口监听
                Socket client = server.accept();
                // 3.创建输入流
                InputStream is = client.getInputStream();
                DataInputStream dis = new DataInputStream(is);
                // 4.接受数据
                System.out.println(client.getInetAddress() + "收到");
                String read = dis.readUTF();
                System.out.println(read);
                // 5.关闭流
                dis.close();
                is.close();
                // 6.关闭Socket
                client.close();
                server.close();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }

2、Client客户端:

  • a、创建Socket对象,指明需要连接的服务器的地址和端口号
  • b、建立连接后,通过输出流向服务器端发送请求信息
  • c、通过输入流获取服务器的响应信息
  • d、关闭相应资源

    package com.bjsxt.socket;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.net.UnknownHostException;
    /**
     * socket客户端(发送数据)      
     * 
     * @author admin
     *
     */
    public class ClientSocket {
    public static void main(String[] args) throws UnknownHostException, IOException {
        System.out.println("客户端已经启动");
        // 1.创建socket对象
        Socket client = new Socket("192.168.88.222",6666);
        // 2.向服务器发送数据(创建输出流对象)
        OutputStream os = client.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        // 3.写数据
        dos.writeUTF("IP地址"+client.getInetAddress().getHostAddress()+"发送消息:HelloWorld");
        // 4.断开输出流
        os.close();
        dos.close();
        // 5.关闭socket
        client.close();
        }
    }
    

TCP通信功能总结:

  • 服务器创建ServerSocket,在指定端口监听并并处理请求;
  • ServletSocket通过accept() 接收用户请求并返回对应的Socket,否则一种处于监听等待状态,线程也被阻塞
    客户端创建Socket,需要指定服务器的ip和端口号,向服务器发送和接收响应

  • 客户端发送数据需要输出流(写),客户端获取反馈数据需要输入流(读)

  • 服务端反馈数据需要输出流(写),服务端获取请求数据需要输入流(读)
  • 一旦使用ServerSocket和Socket建立了网络连接后,网络通信和普通IO流操作并没有太大区别

  • 网络通信输出流建议使用DataOutputStream和ObjectOutputStream,与平台无关,输入流相应使用 DataIntputStream和ObjectInputStream如果是字符串通信也可以使用BufferedReader和PrintWriter,简单方便

UDP编程:

  • 1.UDP没有严格的客户端和服务器端区分,双方是平等的。实现代码也是类似的。
  • 2.主动发起请求的称为客户端,被动接收请求的称为服务器端。
  • 3.UDP编程和IO流没有关系
  • 4.UDP编程的核心类 DatagramSocket:发送或者接收数据报包,DatagramPacket数据报包

代码实例:

    public class AskCliect {
    //客户端类
    public static void main(String[] args) throws IOException {
        // 创建DatagramSocket,用来发送或者接收数据
        DatagramSocket socket = new DatagramSocket(29999); // 接收数据的端口
        Scanner sc = new Scanner(System.in);
        while (true) {//定义循环和Scanner 是为了从键盘循环输入发送的内容。
            String str = sc.nextLine();
            byte[] buf = str.getBytes();
            DatagramPacket packet = new DatagramPacket(buf, buf.length,
            InetAddress.getByName("192.168.88.123"), 20001);
            socket.send(packet); // 发送数据
            byte[] buf1 = new byte[1024];
            // DatagramPacket服务器的接收数据的
            DatagramPacket packet1 = new DatagramPacket(buf1, buf1.length);
            socket.receive(packet1); // 接收数据
            System.out.println("收到的数据:" + new String(packet1.getData()));
            if("bye".equals(str)){//输入bye退出
                break;
            }
        }
        // 关闭资源
        socket.close();
    }
}

.

    public class AskServer {

    public static void main(String[] args) throws IOException {
        // 创建DatagramSocket,用来发送或者接收数据
        DatagramSocket socket = new DatagramSocket(20001); // 端口接收数据的
        Scanner sc = new Scanner(System.in);
        while (true) {//同样为了循环接收数据并且回传消息,实现简单的聊天功能
            byte[] buf = new byte[1024];
            // DatagramPacket服务器的接收数据的
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            socket.receive(packet); // 接收数据
            String info=new String(packet.getData());
            System.out.println("收到的数据:" + info);
            String str = sc.nextLine();
            byte[] buf1 = str.getBytes();
            DatagramPacket packet1 = new DatagramPacket(buf1, buf1.length,
            packet.getAddress(), packet.getPort());
            socket.send(packet1); // 发送数据

            if("bye".equals(info)){  //输入bye退出
                break;
            }
        }
         socket.close();
    }
}

Socket类提供了3个状态测试方法:

  • 1、isClosed():如果Socket已经连接到远程主机,并且还没有关闭,则返回true
  • 2、isConnected():如果Socket曾经连接到远程主机,则返回true
  • 3、isBound():如果Socket已经与一个本地端口绑定,则返回true

如果要判断一个Socket对象当前是否处于连接状态,可以采用以下方式:

boolean isConnected = socket.isConnected()&&!socket.isClosed();

关闭Socket

  • 1、有的时候,可能仅仅希望关闭输出流或输入流之一。此时可以采用Socket类提供的半关闭方法:

    • shutdownInput():关闭输入流。

    • shutdownOutput(): 关闭输出流。

  • 2、注意:先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭了输入流和输出流,并不等价于调用Socket的close()方法。在通信结束后,仍然要调用Socket的close()方法,因为只有该方法才会释放Socket占用的资源,比如占用的本地端口等。

  • 3 Socket类还提供了两个状态测试方法,用来判断输入流和输出流是否关闭:

    • public boolean isInputShutdown();

    • public boolean isOutputShutdown();

—————————————————————————————————————————
笔者知识点有限,如有不足或者错误的地方,还请多多指正。【抱拳】

你可能感兴趣的:(网络编程,java,socket,通信,笔记)