1. 网络编程要素:

  1. 如何定位到网络上的一台或多台主机 IP地址和端口号
  2. 找到后如何通信 TCP/UDP
  3. JAVA,万物皆对象,去找相应的类

2. IP地址

ip地址的包: InetAddress

  • 唯一定位一台网络上的计算机
  • 本机localhost地址: 127.0.0.1
  • ip地址分类:
  • IPV4/IPV6
  • IPV4
  • IPV6
  • 公网-私网
  • ABCD类地址
  • 192.168.xxx.xxx, 给组织内部使用

3. InetAddress包

没有构造函数,只能通过静态方法返回对象

直接查看java文档,获取本机地址/域名地址等,

得到的返回值为一个对象,获取他们的信息

InetAddress localhost = InetAddress.getLocalHost();

localhost.getAddress();
localhost.getcanonicalHostName();
localhost.getHostAddress();
localhost.getHostName();

4. 端口

端口表示计算机上一个程序的进程

  • 不同的进程有不同的端口号,用来区分软件
  • 端口被规定为0--65535
  • TCP/UDP个有65536个,TCP和UDP都有端口80,并且可以同时使用
  • 端口分类:
  • 公有端口:0--1023
  • HTTP 80, HTTPS 443
  • FTP 21, Telent 23
  • 程序注册端口(分配给用户或程序): 1024--49151
  • Tomcat: 8080
  • MySql: 3306
  • Oracle: 1521
  • 动态/私有: 49152-65535(不常用)

常用的Dos命令:

netstat -ano # 查看所有的端口
netstat -ano | findstr 80 #查看指定的端口(|为过滤的意思,把后面的条件带入前面去查找)
tasklist | findstr 8696 # 查看指定端口的进程(去任务管理器查看到PID之后去找)

本机host文件目录: C:\Windows\System32\drivers\etc

InetSocketAddress(ip, port)//有构造方法,可以被调用
//同样的方法返回端口号,ip地址,hostname等

5. 通信协议

TCP:用户传输协议,UDP:用户数据包协议,IP:网络互联协议

  • TCP
  • 连接,稳定
  • 三次握手,四次挥手
    连接--断开流程
A:瞅啥
B:瞅你咋地
A:干一场

A:我要断开了
B: 我知道你要断开了
B: 你真的断开了吗
A:我真的断开了
  • 客户端,服务端
  • 传输完成,释放连接,效率低
  • UDP
  • 不连接,不稳定
  • 客户端,服务端,没有明确的界限
  • 不管有没有准备好,都发过来

6. TCP通信

  • 客户端:
  • 连接服务器 Socket
  • 发送消息(IO流)
  • 服务端:
  • 建立服务端口ServerSocket
  • 等待用户连接 accept
  • 接受用户消息(IO流)
//客户端代码:
public class TcpClientDemo01 {
    public static void main(String[] args){
        InetAddress ServerIP = null;
        Socket socket = null;
        OutputStream os = null;
        try {
            //1. 要知道服务其的地址和端口号
            ServerIP = InetAddress.getByName("127.0.0.1");
            int port = 9999;
            //2. 创建socket通信
            socket = new Socket(ServerIP, port);
            //3. 连接完成后,发送IO流
            os = socket.getOutputStream();
            os.write("whats the fuck".getBytes());

        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if(os!= null) {
                try {
                    os.close();
                    socket.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}
//服务器端代码:
public class TcpServerDemo01 {
    public static void main(String[] args) {
        ServerSocket serverSocket =null;
        Socket socket =null;
        InputStream is =null;
        ByteArrayOutputStream baos =null;
        try {
            //1. 建立客户端要被连接的IP地址和端口号
            serverSocket = new ServerSocket(9999);
            //2. 等待客户端连接
            socket = serverSocket.accept();
            //3. 读取IO流
            is = socket.getInputStream();
            //输入流可能乱码,为防止,套接一个输出流,C输出,S输入,套接一个头输出
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];//定义缓冲区
            int len;
            while((len = is.read(buffer))!=-1){//获得buffer的每一个位置
                baos.write(buffer, 0, len-1);
            }
            System.out.println(baos.toString());
            //finally里面关闭流等管道操作
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(baos != null) {
                try {
                    baos.close();
                    is.close();
                    socket.close();
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

7. TCP文件传输(确定传输完成时间)管道判断

client:! 文件在module下面,不在src目录下面, 在src上一级

public class TcpClient {
    public static void main(String[] args) throws Exception{
        //1.创建socket通信
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
     	//2. 读入文件,写出流
        File test = new File("test.jpg");
        FileInputStream fis = new FileInputStream(test);
        OutputStream fos = socket.getOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer, 0, len);
        }
        //3. socket通知服务器流写出结束
        //通知服务器发送完成是由socket进行的,不是output流
        socket.shutdownOutput();
		//4. 建立输入流,等待服务器接收结束的通知
        InputStream fDidDown = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer2 = new byte[1024];
        int len2;
        while((len2 = fDidDown.read(buffer2))!= -1){
            baos.write(buffer2, 0, len2);
        }
        System.out.println(baos.toString());
		//关闭
        baos.close();
        fDidDown.close();
        fos.close();
        fis.close();
        socket.close();
    }
}

server:

public class TcpServer {
    public static void main(String[] args) throws Exception {
        //1. 创建服务并监听
        ServerSocket serverSocket = new ServerSocket(9999);
        Socket socket = serverSocket.accept();
        //2. 接收输入并保存文件
        InputStream is = socket.getInputStream();
        OutputStream fout = new FileOutputStream(new File("receive.jpg"));
        byte[] buffer = new byte[1024];
        int len;
        while((len = is.read(buffer)) != -1){
            fout.write(buffer, 0, len);
        }
        //3. 输出流通知客户端输出完毕
        OutputStream fHaveDone = socket.getOutputStream();
        fHaveDone.write("文件接收完成".getBytes());
        //关闭
        fHaveDone.close();
        fout.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}

8. Tomcat

tomcat文件目录启动start, 配置文件修改,项目位置:webapps/root

9. UDP通信

用到两个包: DatagramSocket, DatagramPacket

重点:datagramPacket的构造方法,发送端五个参数,接收端3个参数

sender:

  1. 建立socket连接 2. 新建一个数据包 3. 发送 4. 关闭socket通信
public class UdpSender {
    public static void main(String[] args) throws IOException {
        //1. 建立一个socket
        DatagramSocket socket = new DatagramSocket();
        //2. 新建一个包
        String Msg = "a UDP packet";
        byte[] Msg_Byte = Msg.getBytes();
        DatagramPacket dataPacket = new DatagramPacket(Msg_Byte, 0,
                Msg_Byte.length, InetAddress.getByName("127.0.0.1"), 9999);
        //3. 发送包
        socket.send(dataPacket);
        //4. 关闭socket
        socket.close();
    }
}

receiver:

  1. 提供通信 2. 接收数据 3. 操作数据 4. 关闭socket通信
public class UdpReceiver {
    public static void main(String[] args) throws IOException {
        //1. 提供服务
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 接收数据包
        byte[] buffer = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
        socket.receive(datagramPacket);
        //3. 操作数据
        System.out.println(new String(datagramPacket.getData(), 0, datagramPacket.getData().length));
        //4. 关闭socket
        socket.close();
    }
}

10. UDP 聊天实现

低版本: sender可以一直从键盘读取,receiver 可以一直接收

Sender:

public class Sender {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(9999);//本地端口号
        while(true){
            //InputStreamReader参数是键盘输入,把InputStream给bufferedReader, 然后读取下一行
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            String Msg = bufferedReader.readLine();//获取下一个输入
            DatagramPacket datagramPacket = new DatagramPacket(//新建包,要连接的Socket在这里打包
                    Msg.getBytes(), 0, Msg.getBytes().length, new InetSocketAddress("localhost", 9998));
            socket.send(datagramPacket);//发送
            if (Msg.equals("bye")){
                break;
            }
        }
        socket.close();
        System.out.println("聊天结束");
    }
}

Receiver:

public class Receiver {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(9998);//本地端口号
        while(true){
            //接收输入
            byte[] buffer = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
            socket.receive(datagramPacket);
            //把输入转换为String
            String Msg_output = new String(datagramPacket.getData(), 0, datagramPacket.getData().length);
            System.out.println(Msg_output);
            if (Msg_output.equals("bye")){//有问题不能实现
                break;
            }
        }
        System.out.println("聊天结束");
        socket.close();
    }
}

11. 多线程UDP咨询窗口

Java UPD的多线程在线咨询聊天窗口的实现

先写功能块,写一个发送线程和接收线程,( 就是重构,抽取特征,构建成类)

然后创建两个用户,实现这两个方法

Sender

public class Sender implements Runnable{
    private int fromPort;
    private String toIP;
    private int toPort;
    DatagramSocket socket;
    BufferedReader bufferedReader;

    public Sender(int fromPort, String toIP, int toPort) {
        this.fromPort = fromPort;
        this.toIP = toIP;
        this.toPort = toPort;
        try{
            socket = new DatagramSocket(fromPort);
            bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while(true){
            String Msg = null;
            try {
                Msg = bufferedReader.readLine();
                DatagramPacket datagramPacket = new DatagramPacket(
                        Msg.getBytes(), 0, Msg.getBytes().length, new InetSocketAddress(toIP, toPort));
                socket.send(datagramPacket);
                if (Msg.equals("bye")){
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        socket.close();
        System.out.println("聊天结束");
    }
}

Receiver

public class Receiver implements Runnable {
    DatagramSocket socket;
    private int myPort;

    public Receiver(int myPort) {
        this.myPort = myPort;
        try{
            socket = new DatagramSocket(myPort);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while(true){
            byte[] buffer = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
            try {
                socket.receive(datagramPacket);
                String Msg_output = new String(datagramPacket.getData(), 0, datagramPacket.getData().length);
                int FromPort = datagramPacket.getPort();
                System.out.println("["+FromPort + "]" + Msg_output);
                if (Msg_output.equals("bye")){//又问题不能实现
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("聊天结束");
        socket.close();
    }
}

User1

public class User1 {
    public static void main(String[] args) {
        new Thread(new Sender(9991,"localhost",10002)).start();
        new Thread(new Receiver(10001)).start();
    }
}

User2

public class User2 {
    public static void main(String[] args) {
        new Thread(new Sender(9992,"localhost",10001)).start();
        new Thread(new Receiver(10002)).start();
    }
}

12. URL

统一资源定位符:

5部分组成:

#有五部分组成:
协议//:ip地址:端口/项目名称/资源
URL rul = new URL("http://localhost:8080/helloworld/index.jsp?username=kk&password=123");
//很多方法
url.getHost();getProtocol();...

通过URL类下载东西

public class UrlDownload {
    public static void main(String[] args) throws IOException {
        //下载地址
        URL url = new URL("http:loaclhost:8080/projectname/file.txt");
        //连接到这个资源
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        //获得输入流,写到本地
        InputStream inputStream = httpURLConnection.getInputStream();
        FileOutputStream fos = new FileOutputStream("download.txt");
        byte[] buffer = new byte[1024];
        int len;
        while((len = inputStream.read(buffer))!=-1){
            fos.write(buffer, 0, len);
        }
        fos.close();
        inputStream.close();
        httpURLConnection.disconnect();//断开连接
    }
}

(审查元素,去下载收费歌曲)