套接字(Socket)

  • 基本介绍
    • 套接字(Socket)开发网络应用程序被广泛采用,以至于称为事实上的标准
    • 通信的俩端都要有Socket, 是俩台机器间通信的端点
    • 网络通信其实就是Socket间的通信
    • Soket允许程序把网络连接当成一个流, 数据在俩个Soket间通过IO传输
    • 一般主动发起通信的应用程序属客户端, 等待通信请求的为服务端

可以把Socket当做数据通道的俩端插头,当我们需要通讯时(读写数据)

  • socket.getOutputStream()
  • socket.getInputStream()
  • 示意图:

套接字(Socket)_第1张图片

  • 当俩边连接上了,我们客户端就可以用socket.getOutputStream()往数据通道里面写东西
  • 然后我们服务器端也可以拿到对应的socket然后用socket.getInputStream()读数据进来

Socket的理解

  • TCP编程, 可靠的
  • UDP编程, 不可靠的 

应用案例1(使用字节流)

  1. 编写一个服务端和一个客户端
  2. 服务器端在 9999端口监听
  3. 客户端连接到服务器端, 发送"hello,server", 然后退出
  4. 服务器端接收到客户端发送的信息, 输出, 并退出

 服务器端

public class SocketTCP01Server {
    public static void main(String[] args) throws IOException {

        //在本机的 9999端口监听,等待连接
        //  细节: 要求在本机没有其他服务在监听9999
        //  细节: 这个 ServerSocket 可以通过 serverSocket.accept() 返回多个Socket[多并发] 多个客户端连接服务器的并发
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端, 在9999端口监听, 等待连接....");
        //当没有客户端连接9999端口时, 程序会阻塞,等待连接
        //如果有客户端连接,则会返回一个Socket对象, 然后程序继续
        Socket socket = serverSocket.accept();

        System.out.println("服务器端 socket =" + socket.getClass());
        //通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
        InputStream inputStream = socket.getInputStream();
        // IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容
        }
        //关闭流和socket
        inputStream.close();
        socket.close();
        serverSocket.close();//关闭

    }
}

客户端


import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

//客户端 发送"hello ,server" 给服务端
public class SocketTCP01Client {
    public static void main(String[] args) throws IOException {

        //连接服务器(ip, 端口)
        //解读: 连接本机的 9999端口, 如果连接成功返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回 =" + socket.getClass());
        //连接上后, 生成Socket, 通过socket.getOutputStream()
        //  得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //通过数据通道, 写入数据到 数据通道
        outputStream.write("hello, server".getBytes());
        //关闭流对象和socket, 必须关闭
        outputStream.close();
        socket.close();
        System.out.println("客户端退出.....");

    }
}

应用案例2(使用字节流)

  1. 编写一个服务端和一个客户端
  2. 服务器端在 9999端口监听
  3. 客户端连接到服务端, 发送"hello,server", 并接收服务器回发的"hello,client",再退出
  4. 服务器端接收到 客户端发送的 信息, 输出, 并发送"hello, client", 在退出

我们只需要在上一个案例加一点代码就好了,以下

//客户端
OutputStream outputStream = socket.getOutputStream();
        //通过数据通道, 写入数据到 数据通道
        outputStream.write("hello, server".getBytes());
        // 设置一个结束标记
        socket.shutdownOutput();
        outputStream.close();//关闭流
//服务器端
// 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, client".getBytes());
        // 设置一个结束标记
        socket.shutdownOutput();
        outputStream.close();//关闭流

应用案例3(使用字符流完成上面的用例2)

  • 字符流写入需要newLine()插入一个换行符表示回复的内容结束
  • 写入不需要用结束表示,  需要手动刷新 flush()
public class SocketTCP03Server {
    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(9999);
        Socket accept = serverSocket.accept();
        InputStream inputStream = accept.getInputStream();
        OutputStream outputStream = accept.getOutputStream();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String buf = bufferedReader.readLine();
        System.out.println(buf);

        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello,client");
        bufferedWriter.newLine();//插入一个换行符, 表示回复的内容结束
        bufferedWriter.flush();// 注意需要手动刷新flush

        //关闭流
        bufferedWriter.close();
        bufferedReader.close();
        serverSocket.close();
        accept.close();

    }
}
public class SocketTCP03Client {
    public static void main(String[] args) throws IOException {

        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        OutputStream outputStream = socket.getOutputStream();
        InputStream inputStream = socket.getInputStream();

        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello,server");
        bufferedWriter.newLine(); // 插入一个换行符, 表示写入的内容结束, 注意,要求对方使用readLine()!!!
        bufferedWriter.flush(); // 如果使用字符流,需要手动刷新, 否则数据不会写入通道
//        socket.shutdownOutput();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String buf = bufferedReader.readLine();
        System.out.println(buf);

        //关闭流
        bufferedReader.close();
        bufferedWriter.close();
        socket.close();

    }
}

应用实例5

  • 传一张图片
public class TCPFileUploadServer {
    public static void main(String[] args) throws Exception {

        //1. 服务器在本机监听8888
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端在8888端口监听....");
        //2. 等待连接
        Socket socket = serverSocket.accept();


        //3. 读取客户端发送的数据
        //  通过 Socket得到输入流
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //4. 将得到的 bytes 数组,写入到指定的路径, 就得到一个文件了
        String destFilePath = "src\\233.jpg";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
        bos.write(bytes);
        bos.close();

        //向客户端回复"收到照片"
        // 通过socket 获取到输出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("收到图片");
        bw.flush();// 把内容刷新到数据通道
        socket.shutdownOutput();//设置结束标志

        //关闭其他资源
        bw.close();
        bis.close();
        socket.close();
        serverSocket.close();

    }
}
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {

        //创建客户端连接得到Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        //创建读取磁盘文件的输入流
        String filePath = "e:\\233.jpg";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));

        //bytes 就是filePath对应的字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);

        //通过socket获取到输出流,将bytes数据发送给服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道
        bis.close();
        socket.shutdownOutput();// 设置写入数据的结束标记

        //接收从服务器回复的消息
        InputStream inputStream = socket.getInputStream();
        //使用 StreamUtils 的方法, 直接将 InputStream 读取到的内容转成字符串
        String s = StreamUtils.streamToString(inputStream);
        System.out.println(s);


        //关闭相关流
        inputStream.close();
        bos.close();
        socket.close();

    }
}
  • netstat指令
    • netstat -an 可以查看当前主机网络情况, 包括端口监听情况和网络连接情况
    • netstat -an | more 可以分页显示
    • 要求在dos控制台下执行
    • 套接字(Socket)_第2张图片
    •  Listening 表示某个端口在监听
    • 如果有一个外部程序(客户端)连接到该端口, 就会显示一条连接信息.
    • 可以输入ctrl + c 退出程序
  • TCP网络通讯不为人知的秘密
    • 当客户端连接到服务端后, 实际上客户端也是通过一个端口和服务端进行通讯的, 这个端口是TCP/IP来分配的, 是不确定的, 是随机的.
    • 示意图

      • 套接字(Socket)_第3张图片

你可能感兴趣的:(网络,服务器,http)