美文网首页
Java之Socket网络编程

Java之Socket网络编程

作者: 凌云struggle | 来源:发表于2019-08-21 20:48 被阅读0次

Java网络编程

  • 网络编程:指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

URL处理:http://www.baidu.com/search?code=Android&type=1

  • URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。
  • http/https :传输协议 TCP/IP协议
  • www.baidu.com :域名表示一台网络中的电脑
    (ipv4 ipv6 )IP地址:唯一标识一台网络中的计算机
                32位:4个部分 每部分8个字节
  • DNS服务器:域名解析 将www.baidu.com的域名解析为对应的IP地址
  • search:对应的后天程序文件 php java jsp
  • ? 表示运行这个程序需要传递的参数
  • code=Android code是服务器端规定的字段
  • & 如果有多个参数使用&连接

ps:查找自己的电脑IP:win+R进入DOS窗口输入ifconfig即可

  • 数据传输主要通过TCP/IP协议,以下是两种常见的协议:
    • TCP(安全):TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

    • UDP(不安全,但是快):UDP 是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。

Socket 编程

相关概念

  • IP地址:唯一标识某一台电脑

  • 端口号:唯一标识电脑上的某一个进程(程序)80

  • Socket类:客户端 手机应用、浏览器等

  • ServerSocket:服务器端 存储、处理数据

image.png

使用方法:

  • 读取数据:客户端读取 服务器端读取
    BufferedReader->InputStreamReader->socket.getInputStream()
  • 读取终端
    BufferedReader->InputStreamReader->System.in
  • 输出:客户端输出 服务器端输出
    BufferedWriter->OutputStreamWriter->serverSocket.getOutputStream()
    PrintStream(socket.getOutputStream)

1. 实现客户端和服务器端传递数据(注意端⼝号必须相同 先运⾏Server 再运⾏Client)

客户端:(1)创建用于通信的Socket,指明IP地址与端口号。
        (2)使用BufferedReader用循环接收服务器端的数据。
        (3)使用PrintStream向服务器端发送数据,并告诉发送完成socket.shutdownOutput()。
服务器端:(1)创建服务器端的ServerSocket,并指明端口。
          (2)用serverSocket.accept()获取连接客户端的socket。
          (3)用PrintStream向客户端发送数据,完成时使用serverSocket.shutdownOutput()
          (4)使用BufferedReader接收客户端发来的数据

模拟客户端:

//模拟客户端
//10.129.49.204
class Client{
    public static void main(String[] args) throws IOException {
        // 1.创建用于通信的Socket
        //  指明和谁通信:IP地址 端口号
        Socket socket = new Socket("10.129.25.52",8989);
        //接收服务器端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        // 向服务器端发送数据
        // socket.getOutputStream();
        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

        //客户端向服务器端发送数据
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("你好啊!!!");

        socket.shutdownOutput();
    }
}

模拟服务器端:

class Server{
    public static void main(String[] args) throws IOException {
        //1.创建服务器的serversocket
        ServerSocket ss = new ServerSocket(8989);

        //2.获取连接的客户端的socket
        Socket clientSocket = ss.accept();

        //3.向客户端发送数据
        // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
        PrintStream ps = new PrintStream(clientSocket.getOutputStream());
        ps.println("登录成功");

        //输出完毕
        clientSocket.shutdownOutput();

        // 4.接收客户端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}

2. 手动输入内容发送,将输⼊的内容发送给客户端 可以⼀直发

异常处理:如果出现异常,按从小到大关闭资源

两种方式处理异常:

  • 方式1使用if判断语句
 Socket socket = null;
        try {
            socket = new Socket("10.129.49.204",8888);

            //接收服务器端信息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络出错,请重新登录");
        }finally {
            // 关闭连接
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
  • 方式2
 try( ServerSocket serverSocket = new ServerSocket(8888)) {
            // 监听客户端
            Socket socket = serverSocket.accept();

            // 从终端接收数据发送给客户端
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            //获取向客户端输出数据的输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            String line = null;

            while ((line = keyin.readLine()) != null){
                // 发送给客户端
                ps.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
class MyClient{
    public static void main(String[] args){
        //连接服务器端的socket
        Socket socket = null;
        try {
            socket = new Socket("10.129.49.204",8888);

            //接收服务器端信息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }

        } catch (IOException e) {
            System.out.println("网络出错,请重新登录");
        }finally {
            // 关闭连接
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}


class MyServer{
    public static void main(String[] args){
        //创建ServerSocket  自动关闭
        try( ServerSocket serverSocket = new ServerSocket(8888)) {
            // 监听客户端
            Socket socket = serverSocket.accept();

            // 从终端接收数据发送给客户端
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            //获取向客户端输出数据的输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            String line = null;

            while ((line = keyin.readLine()) != null){
                // 发送给客户端
                ps.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

3. 实现客户端向服务器端上传图⽚(字节流)

class Client{
    public static void main(String[] args) throws IOException {
        //链接服务器端  获取socket
        Socket socket = new Socket("10.129.49.204",8080);

        //创建服务器端对应的输入流 用于接受服务器端发来的数据
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
       System.out.println( bufferedReader.readLine());

       //向服务器端发送文件(图片)
        String path = "C:\\Users\\gyl\\Desktop\\1.jpg";
        //1. 将文件写入到内存
        FileInputStream fis = new FileInputStream(path);

        // 2 .创建字节流 outputStream
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        byte[] buffer = new byte[1024];
        int length = -1;
        while ((length = fis.read(buffer)) != -1){
            bos.write(buffer,0,length);
        }
        socket.shutdownOutput();


    }
}


class Server{
    public static void main(String[] args) throws IOException {
        //创建服务器的serverSocket
        ServerSocket serverSocket = new ServerSocket(8080);

        //监听客户端连接
        //当有客户端来连接这个服务器  就可以得到对应的socket
        //当没有客户端来连接 服务器一直在这里等待
        Socket socket = serverSocket.accept();

        //创建客户端对应的输出流对象 用于向这个客户端发送数据
        PrintStream printStream = new PrintStream(socket.getOutputStream());
        printStream.println("连接成功  可以发送数据了");

        // 接收客户端传递过来的图片
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        //文件对应的输出流
        String path = "D:\\AndroidStudioProjects\\JavaCourse\\Java\\src\\main\\java\\day12\\media\\1.jpg";
        FileOutputStream fos = new FileOutputStream(path);

        byte[] buffer = new byte[1024];
        int length = -1;
        while ((length = bis.read(buffer)) != -1){
            fos.write(buffer,0,length);
        }
    }
}

4.使⽤多线程实现对聊

  • 创建一个类实现Runnable接口,重写run方法
  • 创建一个类继承于Thread类,重写run方法
/**
 * 客户端和服务器端可以随意的发送内容
 * 从终端输入
 *
 * 客户端:
 *          主线程:接收终端输入   将终端的输入发送给服务器端
 *          子线程:接收服务器端发送过来的数据
 * 服务器端:
 *          主线程:接收终端输入   将终端的输入发送给客户端
 *           子线程:接收客户端发送过来的数据
 */

class Cilent{
    public static void main(String[] args) throws IOException {
        //链接服务器端 获取socket
        Socket socket = new Socket("10.129.49.204",8888);

        // 用一个子线程处理服务器端的数据
        new Thread(new ClientThread(socket)).start();

        // 主线程处理终端输入发送给服务器端
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        String line = null;

        while ((line = keyin.readLine()) != null){
            ps.println(line);
        }

    }
}


/**
 * 创建一个子线程 处理客户端接收服务器的数据
 */
class ClientThread implements Runnable{
    private Socket socket;
    // 保存socket对象
    public ClientThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            // 获取服务器端的输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

             // 读取数据
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络出错  请重新登录");
            System.exit(-1);
        }finally {
            // 出现异常 关闭资源 从小到大
            try {
            if (br != null){
                    br.close();
                }
            if (socket != null){
                socket.close();
            }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

class Server{
    public static void main(String[] args) throws IOException {
        // 创建服务器端
        ServerSocket ss = new ServerSocket(8888);
        // 获取客户端的socket
        Socket socket = ss.accept();

        // 创建子线程 处理客户端输入信息
        new ServerThread(socket).start();

        //终端输入流对象
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        // 客户端输出流对象
        PrintStream ps = new PrintStream(socket.getOutputStream());
        // 读取终端的输入 将输入输出给客户端
        String line = null;
        while ((line = keyin.readLine()) != null){
            ps.println(line);
        }
    }
}

/**
 *  创建一个子线程处理服务器端接收客户端的书据
 */

class ServerThread extends Thread{
    private Socket socket;
    public ServerThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;

            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
           System.out.println("网络异常  请重新登录");
           System.exit(-1);
        }finally {
            // 关闭输入输出流
            // 关闭对应的socket链接
            try {
                if (br != null) {
                    br.close();
                }
                if (socket != null) {
                    socket.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

5.实现群聊

  • 使用ArrayList 保存每一个连接到的客户端,并且通过循环依次将信息发送给每一个客户端。
class Server{
    // 保存每一个链接过来的对象
    public static ArrayList<Socket> sockets = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);

        //不停地等待客户端来连接
        while (true){
            Socket socket = ss.accept();
            // 当有客户端连接过来了就保存
            sockets.add(socket);

            //开启一个线程处理每个客户端的输入
            new ServerThread(socket).start();

        }

    }
}

/**
 *  创建一个子线程处理服务器端接收客户端的书据
 */

class ServerThread extends Thread{
    private Socket socket;
    public ServerThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;

            while ((line = br.readLine()) != null){
                // 群发消息
                // 遍历Server维护的数组
                for (Socket socket:Server.sockets){
                    // 想socket对应的客户端发送信息
                    PrintStream s = new PrintStream(socket.getOutputStream());
                    s.println(line);
                }
            }
        } catch (IOException e) {
            System.out.println("网络异常  请重新登录");
            System.exit(-1);
        }finally {
            // 关闭输入输出流
            // 关闭对应的socket链接
            try {
                if (br != null) {
                    br.close();
                }
                if (socket != null) {
                    socket.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

class Cilent{
    public static void main(String[] args) throws IOException {
        //链接服务器端 获取socket
        Socket socket = new Socket("10.129.49.204",8888);

        // 用一个子线程处理服务器端的数据
        new Thread(new ClientThread(socket)).start();

        // 主线程处理终端输入发送给服务器端
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        String line = null;

        while ((line = keyin.readLine()) != null){
            ps.println(line);
        }



    }
}

/**
 * 创建一个子线程 处理客户端接收服务器的数据
 */
class ClientThread implements Runnable{
    private Socket socket;
    // 保存socket对象
    public ClientThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            // 获取服务器端的输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // 读取数据
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络出错  请重新登录");
            System.exit(-1);
        }finally {
            // 出现异常 关闭资源 从小到大
            try {
                if (br != null){
                    br.close();
                }
                if (socket != null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

心得体会

  关于客户端和服务器端的操作,刚开始对于输入输出有点绕,不过多写了几遍之后,就更清楚了 ,类似于模板。同时又将多线程的知识融入进来,对知识的理解也更加深刻了。

相关文章

网友评论

      本文标题:Java之Socket网络编程

      本文链接:https://www.haomeiwen.com/subject/ibgisctx.html