Java Socket(慕课网笔记)

Java Socket(慕课网笔记)


网络基础知识

两台主机通过网络进行通信的必备条件:
IP地址、协议、端口号
TCP/IP是目前世界上应用最为广泛的协议
是以TCP和IP为基础的不同层次上多个协议的集合
TCP:传输控制协议 IP:互联网协议
此处输入图片的描述

端口用于区分不同应用程序。端口号范围为0~65535,其中0-1023为系统所保留,自定义可以选其后的
IP地址和端口号组成了Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础
http:80 ftp:21 telnet: 23

针对网络通信的不同层次,java提供的网络功能有四大类:
(1)InetAddress:用于标识网络上的硬件资源(其实就是标识IP地址)
(2)URL: 统一资源定位符 通过URL可以直接读取或写入网络上的数据
(3)Sockets:使用TCP协议实现网络通信的Socket相关的类
(4)Datagram:使用UDP协议,将数据保存在数据报中,通过发送数据报在网络进行通信

InetAddress类

无构造函数,但有一些静态方法,返回InetAddress的实例

public class Test01 {
    public static void main(String[] args) throws UnknownHostException{
        //获取本机的InetAddress实例
        InetAddress address=InetAddress.getLocalHost();
        System.out.println("计算机名"+address.getHostName());
        System.out.println("IP地址"+address.getHostAddress());
        byte[] bytes = address.getAddress(); // 获取字节数组形式的IP地址
        System.out.println("字节数组形式的IP"+Arrays.toString(bytes));
        System.out.println(address);
        // 根据主机名获取InetAddress实例
        InetAddress address2= InetAddress.getByName("DESKTOP-AK4BLPN");
        //一样
        //InetAddress address2= InetAddress.getByName("192.168.89.1");
        System.out.println("计算机名"+address2.getHostName());
        System.out.println("IP地址"+address2.getHostAddress());

    }
}

output:
计算机名DESKTOP-AK4BLPN
IP地址192.168.89.1
字节数组形式的IP[-64, -88, 89, 1]
DESKTOP-AK4BLPN/192.168.89.1
计算机名DESKTOP-AK4BLPN
IP地址192.168.89.1

URL

表示Internet上某一资源的地址
两部分组成:协议名称和资源名称,以冒号隔开
此处输入图片的描述
在java.net包中,提供了URL类来表示URL

public class Test02 {
    public static void main(String[] args){
        try {
            //创建一个URL实例
            URL imooc = new URL("http://www.imooc.com");
            URL url = new URL(imooc,"/index.html?username=tom#test");   
            //?后表示参数的信息,#后表锚点
            System.out.println("协议"+url.getProtocol());
            System.out.println("主机"+url.getHost());
            System.out.println("端口"+url.getPort());
            System.out.println("文件路径"+url.getPath());
            System.out.println("文件名"+url.getFile());
            System.out.println("相对路径"+url.getRef());
            System.out.println("查询字符串"+url.getQuery());
        } catch (MalformedURLException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

协议http
主机www.imooc.com
端口-1
文件路径/index.html
文件名/index.html?username=tom
相对路径test
查询字符串username=tom

注:如果未指定端口号,则使用默认端口号,这里http默认是80端口,此时getPort()方法返回值为-1

通过URL读取网页内容

通过URL对象的openStream()方法可以得到指定资源的输入流通过输入流可以读取、访问网络上的数据

public class Test03 {
    public static void main(String[] args){
        //创建一个URL实例
        try {
            URL url =new URL("http://www.baidu.com");
            //通过URL的openStream方法获取URL对象所表示的资源的字节输入流
            InputStream is = url.openStream();
            //将字节输入流转换为字符输入流
            InputStreamReader isr = new InputStreamReader(is,"utf-8"); // 指定编码
            //为字符输入流添加缓冲,提高读取效率
            BufferedReader br = new BufferedReader(isr);
            String data=br.readLine();
            while(data!=null){
                System.out.println(data);
                data = br.readLine();
            }
            br.close();
            isr.close();
            is.close();

        } catch (MalformedURLException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }

    }
}

Socket通信(TCP编程)

TCP协议是面向连接的、可靠的、有序的,以字节流的方式发送数据
基于TCP协议实现网络通信的类:
客户端的Socket类
服务器端的ServerSocket类
此处输入图片的描述
Socket通信实现步骤:
1.创建ServerSocket和Socket
2.打开连接到Socket的输入/输出流
3.按照协议对Socket进行读/写操作
4.关闭输入输出流、关闭Socket

服务器端
1、创建ServerSocket对象,绑定监听端口
2、通过accept()方法监听客户端请求
3、连接建立后,通过输入流读取客户端发送的请求信息
4、通过输出流向客户端发送响应信息
5、关闭相关资源

客户端
1、创建Socket对象,指明需要连接的服务器的地址和端口号
2、连接建立后,通过输出流向服务器端发送请求信息
3、通过输入流获取服务器响应的信息
4、关闭相关资源
实例:
先开启服务端,后开启客户端

/*
 * 基于TCP协议的socket通信,实现用户登录
 */
public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("***服务器即将启动,等待客户端连接***");
            Socket socket = serverSocket.accept();
            // 获取输入流,并读取客户端信息
            InputStream is = socket.getInputStream(); // 字节输入流
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String info = null;
            while((info = br.readLine()) != null) {
                System.out.println("我是服务器,客户端说:" + info);
            }
            socket.shutdownInput(); // 关闭输入流

            // 获取输出流,响应客户端的请求
            OutputStream os = socket.getOutputStream(); 
            PrintWriter pw = new PrintWriter(os); 
            pw.write("欢迎你");
            pw.flush();

            // 关闭资源
            pw.close();
            os.close();
            br.close();
            isr.close();
            is.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } 
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        try {
            // 创建客户端socket,指定服务器地址和端口
            Socket socket = new Socket("localhost",8888);
            // 获取输出流,向服务器端发送信息
            OutputStream os = socket.getOutputStream(); 
            PrintWriter pw = new PrintWriter(os); // 将输出流包装为打印流
            pw.write("用户名: admihn;密码:123");
            pw.flush();//刷新缓存,向服务器端输出信息
            socket.shutdownOutput(); 

            InputStream is = socket.getInputStream(); // 字节输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String info = null;
            while((info = br.readLine()) != null) {
                System.out.println("我是客户端,服务器端说:" + info);
            }

            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (UnknownHostException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }

    }
}
多线程实现客户端通信

应用多线程实现服务器与多客户端之间的通信
注: 未设置优先级可能会导致运行时速度非常慢,可降低优先级
基本步骤:
1、服务器端创建ServerSocket,循环调用accept()等待客户端连接
2、客户端创建一个socket并请求和服务器端连接
3、服务器端接收客户端请求,创建socket与该客户建立专线连接
4、建立连接的两个socket在一个单独的线程上对话
5、服务器端继续等待新的连接
客户端不变

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            Socket socket = null;
            System.out.println("***服务器即将启动,等待客户端连接***");
            // 记录客户端数量
            int count = 0;

            // 循环监听等待客户端的连接
            while(true) {
                socket = serverSocket.accept();
                // 创建一个新的线程
                ServerThread serverThread = new ServerThread(socket);
                thread.setPriority(4);// 设置线程的优先级,范围为[1,10],默认为5
                serverThread.start();

                count++; // 统计客户端数量
                System.out.println("客户端数量为" + count);
                InetAddress address = socket.getInetAddress();
                System.out.println("当前客户端IP:" + address.getHostAddress());
            }
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } 
    }
}


/*
 * 服务器线程处理类
 */
public class ServerThread extends Thread{
    // 和本线程相关的socket
    Socket socket = null;
    public ServerThread(Socket socket) {
        this.socket = socket;
    }
    // 线程执行的操作,响应客户端的请求
    public void run() {
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        PrintWriter pw = null;
        try {
            // 获取输入流,并读取客户端信息
            is = socket.getInputStream();// 字节输入流
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            String info = null;
            while((info = br.readLine()) != null) {
                System.out.println("我是服务器,客户端说:" + info);
            }
            socket.shutdownInput(); // 关闭输入流

            // 获取输出流,响应客户端的请求
            os = socket.getOutputStream(); 
            pw = new PrintWriter(os); 
            pw.write("欢迎你");
            pw.flush();

        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } finally{
            // 关闭资源
            try {
                if(pw != null)
                    pw.close();
                if(os != null)
                    os.close();
                if(br != null)
                    br.close();
                if(isr != null)
                    isr.close();
                if(is != null)
                    is.close();
                if(socket != null)
                    socket.close();
                } catch (IOException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }

        }
    }
}
/*
客户端
*/

public class Client {
    public static void main(String[] args) {
        try {
            // 创建客户端socket,指定服务器地址和端口
            Socket socket = new Socket("localhost",8888);
            // 获取输出流,向服务器端发送信息
            OutputStream os = socket.getOutputStream(); 
            PrintWriter pw = new PrintWriter(os); // 将输出流包装为打印流
            pw.write("用户名: admihn;密码:123");
            //pw.write("用户名: scyda;密码:121");
            pw.flush();//刷新缓存,向服务器端输出信息

            // pw.close(); // 不能关闭输出流,会导致socket也被关闭
            socket.shutdownOutput(); 

            InputStream is = socket.getInputStream(); // 字节输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String info = null;
            while((info = br.readLine()) != null) {
                System.out.println("我是客户端,服务器端说:" + info);
            }

            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (UnknownHostException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }

    }
}

对于同一个Socket,如果关闭了输出流,则与该输出流关联的socket也会被关闭,所以一般不用关闭流,直接关闭socket即可
使用TCP传输对象

// 创建客户端socket,指定服务器地址和端口
            Socket socket = new Socket("localhost",8888);
            // 获取输出流,向服务器端发送信息
            OutputStream os = socket.getOutputStream(); 
            // 使用objectOutputStream对象序列化流,传递对象
            ObjectOutputStream oos = new ObjectOutputStream(os); 
            User user = new User("admin", "123"); // 封装为对象
            oos.writeObject(user); // 序列化
            socket.shutdownOutput();

            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String info = null;
            while((info = br.readLine()) != null) {
                System.out.println("我是客户端,服务器端说:" + info);
            }   

此处输入图片的描述

UDP编程

UDP协议(用户数据报协议)是无连接、不可靠、无序的
进行数据传输时,首先需要将要传输的数据定义为数据报(Datagram),在数据报中指明数据所要达到的Socket(主机地址和端口号),然后将数据报发送出去

DatagramPacket:表示数据报包
DatagramSocket:进行端到端通信的类

服务器端:
1. 创建DatagramSocket,指定端口号
2. 创建DatagramPacket
3. 接收客户端发送的数据信息
4. 读取数据

客户端:
1. 定义发送信息
2. 创建DatagramPacket,包含将要发送的信息
3. 创建DatagramSocket
4. 发送数据

public class UDPServer {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(8800);
        // 2. 创建数据报,用于接收客户端发送的数据
        byte[] data = new byte[1024]; // 创建字节数组,指定接收的数据包的大小
        DatagramPacket packet = new DatagramPacket(data, data.length);
        System.out.println("服务器已启动,等待客户端发送数据");
        socket.receive(packet); // 此方法在接收到数据报之前会一直阻塞

        String info = new String(data, 0, packet.getLength());
        System.out.println("服务器,客户端说:" + info);

        /*
         * 向客户端响应数据
         */
        // 定义客户端的地址、端口号、数据
        InetAddress address = packet.getAddress(); // 通过数据报获取
        int port = packet.getPort();
        byte[] data2 = "welcome".getBytes();
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
        socket.send(packet2);

        // 关闭资源
        socket.close();
    }
}
public class UDPClient {
    public static void main(String[] args) throws IOException {
        // 定义服务器的地址、端口号、数据
        InetAddress address = InetAddress.getByName("localhost");
        int port = 8800;
        byte[] data = "用户名:admin,密码:123".getBytes();

        DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
        DatagramSocket socket = new DatagramSocket();
        socket.send(packet);
        /*
         * 接收服务器端的响应
         */
        // 1. 创建数据报,用于接收服务端发送的数据
        byte[] data2 = new byte[1024];
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
        // 接收服务端响应的数据
        socket.receive(packet2);
        // 读取数据
        String info = new String(data2, 0, packet2.getLength());
        System.out.println("客户端,服务器说:" + info);
        // 关闭资源
        socket.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值