Web初体验--Socket网络编程

java网络编程基础知识

通信协议:计算机网络中实现通信必须有一些约定,即通信协议。对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。
TCP协议:提供可靠的数据传输服务;(传输层)
IP协议: 进行IP数据包的分割和组装。(应用层)

IP地址和端口号

1、IP地址:为实现网络中不同的计算机之间的通信,在网络中的每台机器都必须有一个与众不同的标识,这就是IP地址(IP Address)。
格式:数字型、32位、由4段8位的二进制数组成。一般表示为十进制形式(4个0~255的十进制整数),中间用圆点隔开。如:166.111.78.98
域名地址:也是分段表示的,便于记忆的、字符串形式。
DNS服务器:域名服务器(解析器)
将www.baidu.com类型的域名解析为对应的IP地址
*2、端口:一个16位的整数,用于表示数据交给哪个通信程序处理。因此,端口就是应用程序与外界交流的出入口,它是一种抽象的软件结构,包括一些数据结构和I/O(基本输入/输出)缓冲区。
不同的应用程序处理不同端口上的数据,同一台机器上不能有两个程序使用同一个端口,端口号可以从0到65535,通常将它分为三类:
*、公认端口(Well Known Ports):从0到1023,它们紧密绑定(Binding)一些服务。
*、注册端口(Registered Ports):从1024到49151。它们松散地绑定一些服务。
*、动态和/或私有端口(Dynamic and/or Private Ports):从49152到65535,这些端口是应用程序使用的动态端口,应用程序一般不会主动使用这些端口。

TCP\UDP协议

1、TCP是Tranfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个 socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送 或接收操作。
2、UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

比较:
UDP:

1, 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
2, UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
3, UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方

TCP:

1, 面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接时间。
2, TCP传输数据大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大的数据。
3, TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。

Demo1:客户端向服务器端上传图片
class Client{
    public static  void main (String []args) throws IOException {
      //连接服务器端  获取socket
      Socket socket = new Socket("127.0.0.1",8080);
      // 创建服务器端对应的输入流 用于接受向服务器端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        System.out.println(br.readLine());
        //向服务器端发送文件(图片)
        // 1.将文件写入内存
        String path = "C:/Users/12931/Pictures/1.jpg";
        FileInputStream fis = new FileInputStream(path);
        //将内容输出到服务器端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        //3.将文件的内容一点一点的传输给服务器
        byte [] buf = new byte[1024];
        int len = -1;
        while ((len = fis.read(buf))!=-1){
            bos.write(buf,0,len);
        }
        socket.shutdownOutput();
     }
}

class Server{
    public static  void main (String []args) throws IOException {
        ServerSocket ss = new ServerSocket(8080);
        // 监听客户端连接
        // 当有客户端来连接这个服务器就可以得到对应的socket
        //当没有客户端来连接  服务器一直在这里等待
        Socket socket = ss.accept();
        //创建客户端对应的输出流  用于向客户端发送数据
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("连接成功  可以发送数据了");

        //接收客户端传递过来的图片
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        //文件对应的输出流
        String path = "D:/Java learning/java/src/main/java/day12/1.jpg";
        FileOutputStream fos = new FileOutputStream(path);
        byte [] buf = new byte[1024];
        int len = -1;
        //写入文件
        while ((len = bis.read(buf))!=-1){
            fos.write(buf,0,len);
        }
    }
}

注:实现客户端和服务器器端传递数据: 注意端⼝口号必须相同 先运行Server 再运行Client

使用多线程实现对聊

功能:客户端和服务器都可以随意地发送内容
使用多线程实现如下操作:
客户端操作:
主线程:接收终端输入 将终端的输入发送给服务器端
子线程:接收服务器端发过来的数据
服务器端:
主线程:接受终端输入 将终端输入发送给客户端
子线程:接收客户端发过来的数据


Web初体验--Socket网络编程_第1张图片
image.png
class Client{
    public static  void main(String [] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",6665);
        //主线程处理终端输入发送给服务器端
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        //用一个子线程处理服务器端数据
        new Thread( new ClientThread(socket)).start();
        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(6665);
        //获取客户端的socket
        Socket socket = ss.accept();

        //终端输入流对象
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        //创建子线程 梳理客户输入信息
         new ServerThread(socket).start();

        //客户端的输出流对象
        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();
            }
        }
    }
}

用多线程实现群聊

1.在对聊的基础上更改Server类,使其不停的等待客户端来连接
2.用数组保存所来连接的客户端
3.更改ServerThread类,将服务器接收到的全部消息发给每一个客户端


Web初体验--Socket网络编程_第2张图片
image.png
/**
 *1.如何实现群聊
 *   在服务器端维护一个数组{socket}
 *   2.私聊
 */
class Server{
    //保存每一个连接过来的socket对象
    public static ArrayList sockets = new ArrayList<>();
    public static  void main(String [] args) throws IOException {
        ServerSocket ss = new ServerSocket(6666);

        //不停的等待客户端来连接
        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){
                //群发消息

                for(Socket s :Server.sockets){
                    PrintStream ps =new PrintStream(s.getOutputStream());
                    ps.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 Client{
    public static  void main(String [] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",6666);

        //主线程处理终端输入发送给服务器端
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        //用一个子线程处理服务器端数据
        new Thread( new day12.ClientThread(socket)).start();
        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();
            }
        }
    }
}

感悟: 有时候因为手速问题,自己敲代码不够快,导致 上面讲的时候自己又在跟着敲代码,听的就不是很认真,会错过些东西,可能还是自己敲代码敲得少吧。今天把所有的Demo都敲了两遍之后才理解的差不多,感觉在学新东西之前还是要先预习一下才能听的好。

你可能感兴趣的:(Web初体验--Socket网络编程)