网络编程

一、什么是网络编程

二、基本的通信架构

三、网络通信的三要素

1.IP地址

1.IPv4,IPv6

2.IP域名

3.公网IP ,内网IP,本机IP

4.InetAddress

java 复制代码
import java.net.InetAddress;


public class InetAddressTest {
    public static void main(String[] args) throws Exception {
        //获取本机IP地址对象
        InetAddress ip1 = InetAddress.getLocalHost ();
        System.out.println ( ip1.getHostAddress () );//获取本机IP地址
        System.out.println ( ip1.getHostName () );//获得主机名

        //2.获取指定IP地址或者域名的对象
        InetAddress ip2 = InetAddress.getByName ( "WWW.baidu.com" );
        System.out.println ( ip2.getHostName () );//WWW.baidu.com
        System.out.println ( ip2.getHostAddress () );//39.156.66.14
        System.out.println ( ip2.isReachable ( 6000 ) );//判断能否联通
    }
}

2.端口号

3.协议

1.什么是协议

2.UDP协议

3.TCP协议

四、网络通信

1.UDP通信

1.常用API
2.代码
java 复制代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建客户端对象(发送方)
        DatagramSocket socket = new DatagramSocket (7777);
        //2.创建数据包对象封装要发出去的数据
//        DatagramPacket(byte[], int length,InetAddress,int port)
/** byte[]:代表要传输的数据
 *  int length:发出去数据的大小
 *  InetAddress:服务端的IP地址
 *  int port:服务端程序的端口号
 *
 */
        byte[] bytes = "我是快乐的客户端,我爱你abc".getBytes ();
        DatagramPacket packet = new DatagramPacket (bytes,bytes.length, InetAddress.getLocalHost (),6666 );
        //3.开始正式发送数据包出去
        socket.send ( packet );
        System.out.println ("客户端数据发送完毕");
        socket.close ();//释放资源


    }
}


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Server {
    public static void main(String[] args) throws Exception {
    //1.创建一个服务端对象并注册端口
        DatagramSocket server = new DatagramSocket ( 6666 );
    //2.创建一个数据包对象,用于接受数据
        byte[] bytes = new byte[1024*64];//64kb
        DatagramPacket packet = new DatagramPacket (bytes,bytes.length);
     //3.接收客户端发来的数据
     server.receive ( packet );
     //4.把字节数组中,接受的数据打印出来
        //读取多少倒出多少
        //获取本次数据包接收了多少数据
        int length = packet.getLength ();
        //通过数据包拿到客户端的IP地址
        System.out.println ( packet.getAddress ().getHostAddress () );
        //通过数据包拿到客户端的端口号
        System.out.println ( packet.getPort () );
        String s = new String ( bytes,0,length );
        System.out.println ( s );
        server.close ();
    }
}
3.UDP通信-多发多收
java 复制代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建客户端对象(发送方)
        DatagramSocket socket = new DatagramSocket ();
        //2.创建数据包对象封装要发出去的数据
//        DatagramPacket(byte[], int length,InetAddress,int port)
/** byte[]:代表要传输的数据
 *  int length:发出去数据的大小
 *  InetAddress:服务端的IP地址
 *  int port:服务端程序的端口号
 *
 */
        Scanner sc=new Scanner ( System.in );
        while (true) {
            System.out.println ("请说:");
            String msg = sc.nextLine ();
            byte[] bytes1 = msg.getBytes ();
            byte[] bytes = "我是快乐的客户端,我爱你abc".getBytes ();
            DatagramPacket packet = new DatagramPacket (bytes1,bytes1.length, InetAddress.getLocalHost (),6666 );
            //3.开始正式发送数据包出去
            socket.send ( packet );
            if ("exit".equals ( msg )){
                System.out.println ("欢迎下次光临,退出成功");
                break;
            }
        }


    }
}


import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
    public static void main(String[] args) throws Exception {
    //1.创建一个服务端对象并注册端口
        DatagramSocket server = new DatagramSocket ( 6666 );
    //2.创建一个数据包对象,用于接受数据
        byte[] bytes = new byte[1024*64];//64kb
        DatagramPacket packet = new DatagramPacket (bytes,bytes.length);
     //3.接收客户端发来的数据
        while (true) {
            server.receive ( packet );
            //4.把字节数组中,接受的数据打印出来
            //读取多少倒出多少
            //获取本次数据包接收了多少数据
            int length = packet.getLength ();
            //通过数据包拿到客户端的IP地址
            System.out.println ( packet.getAddress ().getHostAddress () );
            //通过数据包拿到客户端的端口号
            System.out.println ( packet.getPort () );
            String s = new String ( bytes,0,length );
            System.out.println ( s );
            System.out.println ("--------------------------------------------------------------------");
        }

    }
}

2.TCP通信

1.如何实现TCP通信
2.客户端开发
java 复制代码
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建Socket对象,并同时请求服务器端程序的连接
        Socket socket = new Socket ("127.0.0.1",8888);
        //2.从socket管道中得到一个字节输出流,用来发送数据给服务端
        OutputStream os = socket.getOutputStream ();
        //3.把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream ( os );
        //4.开始写数据出去
        dos.writeUTF ( "在一起好吗?" );
        dos.close ();
        socket.close ();
    }
}
3.服务端开发
java 复制代码
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println ("----------服务端启动成功");
        //1.创建一个服务端对象并设置端口号
        ServerSocket serverSocket = new ServerSocket ( 8888 );
        //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept ();
        //3.从socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream ();
        //4.把原始字字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream ( is );
        //5.使用数据输入流读取客户端发送的消息
        String s = dis.readUTF ();
        System.out.println ( s );
        //获取客户端的IP地址
        System.out.println ( socket.getRemoteSocketAddress () );
        dis.close ();
        socket.close ();


    }
}
4.多发多收
java 复制代码
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建Socket对象,并同时请求服务器端程序的连接
        Socket socket = new Socket ("127.0.0.1",8888);
        //2.从socket管道中得到一个字节输出流,用来发送数据给服务端
        OutputStream os = socket.getOutputStream ();
        //3.把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream ( os );
        //4.开始写数据出去
        Scanner scanner = new Scanner (System.in);
        while (true) {
            System.out.println ("请说");
            String s = scanner.nextLine ();
            dos.writeUTF ( s );
            dos.flush ();
            if ("exit".equals ( s )){
                System.out.println ("欢迎下次使用,成功退出");
                dos.close ();
                socket.close ();
            }
        }

    }
}


import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println ("----------服务端启动成功");
        //1.创建一个服务端对象并设置端口号
        ServerSocket serverSocket = new ServerSocket ( 8888 );
        //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept ();
        //3.从socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream ();
        //4.把原始字字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream ( is );
        //5.使用数据输入流读取客户端发送的消息
        while (true) {
            try {
                String s = dis.readUTF ();
                System.out.println ( s );
                //获取客户端的IP地址
                System.out.println ( socket.getRemoteSocketAddress () );
                System.out.println ("--------------------------------------");
            } catch (IOException e) {
                System.out.println ( socket.getRemoteSocketAddress () + "离线了" );
                socket.close ();
                dis.close ();
                break;
            }
        }



    }
}
5.支持与多个客户端同时通信(上下线逻辑)
java 复制代码
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class ServerReaderThread extends Thread{
    private  Socket socket;
    public ServerReaderThread(){

    }
    public ServerReaderThread(Socket socket){
    this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream ();
            DataInputStream dis = new DataInputStream ( is );
            while (true) {
                try {
                    String s = dis.readUTF ();
                    System.out.println ( s );
                } catch (Exception e) {

                    System.out.println ("下线了"+socket.getRemoteSocketAddress ());
                    dis.close ();
                    socket.close ();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace ();
        }
    }
}


import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建Socket对象,并同时请求服务器端程序的连接
        Socket socket = new Socket ("127.0.0.1",8888);
        //2.从socket管道中得到一个字节输出流,用来发送数据给服务端
        OutputStream os = socket.getOutputStream ();
        //3.把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream ( os );
        //4.开始写数据出去
        Scanner scanner = new Scanner (System.in);
        while (true) {
            System.out.println ("请说");
            String s = scanner.nextLine ();
            dos.writeUTF ( s );
            dos.flush ();
            if ("exit".equals ( s )){
                System.out.println ("欢迎下次使用,成功退出");
                dos.close ();
                socket.close ();
            }
        }

    }
}




import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println ("----------服务端启动成功");
        //1.创建一个服务端对象并设置端口号
        ServerSocket serverSocket = new ServerSocket ( 8888 );

        while (true) {
            //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept ();
            System.out.println (socket.getRemoteSocketAddress ()+"上线了");
            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerReaderThread (socket).start ();
        }


    }
}

五、TCP 通信综合案例

1.即使通信-群聊

java 复制代码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ClientReaderThread extends Thread{
    private Socket socket;
    public ClientReaderThread(){

    }
    public ClientReaderThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream ();
            DataInputStream dis = new DataInputStream ( is );
            while (true) {
                try {
                    String s = dis.readUTF ();
                    System.out.println ( s );
                    //把这个消息发给全部的客户端进行接受
                    sendMsgAll(s);
                } catch (Exception e) {

                    System.out.println ("自己下线了"+socket.getRemoteSocketAddress ());

                    dis.close ();
                    socket.close ();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace ();
        }

    }
    private void sendMsgAll(String s) throws Exception {
        //发送给全部在线的Socket对象
        for (Socket onLineSocket : Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream ();
            DataOutputStream dos = new DataOutputStream ( os );
            dos.writeUTF ( s );
            dos.flush ();
        }}
}

import java.io.*;
import java.net.Socket;

public class ServerReaderThread extends Thread{
    private  Socket socket;
    public ServerReaderThread(){

    }
    public ServerReaderThread(Socket socket){
    this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream ();
            DataInputStream dis = new DataInputStream ( is );
            while (true) {
                try {
                    String s = dis.readUTF ();
                    System.out.println ( s );
                    //把这个消息发给全部的客户端进行接受
                    sendMsgAll(s);
                } catch (Exception e) {

                    System.out.println ("下线了"+socket.getRemoteSocketAddress ());
                    Server.onLineSockets.remove ( socket );//离线时抹掉Socket
                    dis.close ();
                    socket.close ();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace ();
        }
    }

    private void sendMsgAll(String s) throws Exception {
        //发送给全部在线的Socket对象
        for (Socket onLineSocket : Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream ();
            DataOutputStream dos = new DataOutputStream ( os );
            dos.writeUTF ( s );
            dos.flush ();
        }
    }
}

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建Socket对象,并同时请求服务器端程序的连接
        Socket socket = new Socket ("127.0.0.1",8888);
        //创建一个独立的线程,负责随时从socket中接受来自服务端的消息
        new ClientReaderThread (socket).start ();

        //2.从socket管道中得到一个字节输出流,用来发送数据给服务端
        OutputStream os = socket.getOutputStream ();
        //3.把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream ( os );
        //4.开始写数据出去
        Scanner scanner = new Scanner (System.in);
        while (true) {
            System.out.println ("请说");
            String s = scanner.nextLine ();
            dos.writeUTF ( s );
            dos.flush ();
            if ("exit".equals ( s )){
                System.out.println ("欢迎下次使用,成功退出");
                dos.close ();
                socket.close ();
            }
        }

    }
}



import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {
    public static List<Socket> onLineSockets=new ArrayList<> ();
    public static void main(String[] args) throws Exception {
        System.out.println ("----------服务端启动成功");
        //1.创建一个服务端对象并设置端口号
        ServerSocket serverSocket = new ServerSocket ( 8888 );

        while (true) {
            //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept ();
        onLineSockets.add ( socket );//有连接就存储Socket管道
            System.out.println (socket.getRemoteSocketAddress ()+"上线了");
            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerReaderThread (socket).start ();
        }


    }
}

2.实现一个简易的BS架构

B/S架构
java 复制代码
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {
    public static List<Socket> onLineSockets=new ArrayList<> ();
    public static void main(String[] args) throws Exception {
        System.out.println ("----------服务端启动成功");
        //1.创建一个服务端对象并设置端口号
        ServerSocket serverSocket = new ServerSocket ( 8888 );

        while (true) {
            //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept ();
        onLineSockets.add ( socket );//有连接就存储Socket管道
            System.out.println (socket.getRemoteSocketAddress ()+"上线了");
            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            new ServerReaderThread (socket).start ();
        }


    }
}



import java.io.*;
import java.net.Socket;

public class ServerReaderThread extends Thread{
    private  Socket socket;
    public ServerReaderThread(){

    }
    public ServerReaderThread(Socket socket){
    this.socket=socket;
    }
    @Override
    public void run() {
       //立即响应一个网页内容:"黑马程序员"给浏览器提示
        try {
            OutputStream os = socket.getOutputStream ();
            PrintStream ps = new PrintStream ( os );
            ps.println ("HTTP/1.1 200 OK");
            ps.println ("Content-Type:text/html;charset=UTF-8");
            ps.println ();//必须换行
            ps.println ("<div >黑马666</div>");
            socket.close ();//响应网页短连接

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


}
使用线程池优化
java 复制代码
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Server {
    public static List<Socket> onLineSockets=new ArrayList<> ();
    public static void main(String[] args) throws Exception {
        System.out.println ("----------服务端启动成功");
        //1.创建一个服务端对象并设置端口号
        ServerSocket serverSocket = new ServerSocket ( 8888 );
        //创建一个线程池,负责处理通信管道的任务
        ThreadPoolExecutor pool = new ThreadPoolExecutor (16*2,16*2,0, TimeUnit.SECONDS,
        new ArrayBlockingQueue<> ( 8 ), Executors.defaultThreadFactory (),new ThreadPoolExecutor.AbortPolicy () );

        while (true) {
            //2.使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept ();
        onLineSockets.add ( socket );//有连接就存储Socket管道
            System.out.println (socket.getRemoteSocketAddress ()+"上线了");
            //3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
            //把通信管道封装成任务对象
            pool.execute ( new ServerReaderRunnable (socket));

        }


    }
}



import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

public class ServerReaderRunnable implements Runnable{
    private  Socket socket;
    public ServerReaderRunnable(){

    }
    public ServerReaderRunnable(Socket socket){
    this.socket=socket;
    }
    @Override
    public void run() {
       //立即响应一个网页内容:"黑马程序员"给浏览器提示
        try {
            OutputStream os = socket.getOutputStream ();
            PrintStream ps = new PrintStream ( os );
            ps.println ("HTTP/1.1 200 OK");
            ps.println ("Content-Type:text/html;charset=UTF-8");
            ps.println ();//必须换行
            ps.println ("<div >黑马666</div>");
            socket.close ();//响应网页短连接

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


}
相关推荐
Zfox_4 分钟前
【Linux】进程信号全攻略(二)
linux·运维·c语言·c++
速盾cdn4 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
安於宿命9 分钟前
【Linux】简易版shell
linux·运维·服务器
丶Darling.12 分钟前
MIT 6.S081 Lab1: Xv6 and Unix utilities翻译
服务器·unix·lab·mit 6.s081·英文翻译中文
追梦不止~16 分钟前
Docker常用命令+详解
运维·docker·容器
黑龙江亿林等保19 分钟前
深入探索哈尔滨二级等保下的负载均衡SLB及其核心算法
运维·算法·负载均衡
黄小耶@20 分钟前
linux常见命令
linux·运维·服务器
叫我龙翔21 分钟前
【计网】实现reactor反应堆模型 --- 框架搭建
linux·运维·网络
古驿幽情24 分钟前
CentOS AppStream 8 手动更新 yum源
linux·运维·centos·yum
BillKu25 分钟前
Linux(CentOS)安装 Nginx
linux·运维·nginx·centos