Java网络编程---Socket

来源:互联网 发布:淘宝分销货源平台 编辑:程序博客网 时间:2024/05/18 23:26

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();

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