枚举,网络编程

枚举

枚举: 列举出 有穷序列集
枚举类其实用了多例模式,枚举类的实例是有范围限制的。
enum类,反编译后就是一个 class 继承了Enum(注意:我们不能显示继承这个Enum),如果枚举类里定义了抽象方法,他就是abstract类,如果没有抽象方法,他就由final修饰。final修饰的类不能被继承

enum Gender{
	MALE,FEMALE;
}

反编译后大概是这样,必须看

public final class Gender extends java.lang.Enum {
 
  public static final Gender Male;
  public static final Gender Female;
  //为了确保只有固定个数对象且不能被修改,所以用static final修饰
 
  private static final Gender[] $VALUES;
 //这个是一个放所有枚举对象的数组,用values可以获取到。在编译阶段由编译器添加的,包括values()方法
 
  static {//静态代码块,加载类的时候,就挨个创建每个枚举对象,并放进数组里。
    Male = new Gender("Male", 0);
    Female = new Gender("Female", 1);
 
    $VALUES = new Gender[] {Male, Female};
  }

  //编译器会把构造方法设置成下面这样,name是对应的名字,original是索引,从0开始。继承的Enum类中有对应的方法获取名字和索引
  private Gender(String name, int original) {
    super(name, original)
  }
 
 //这个就是编译器加的values方法,clone()的拓展在后边
  public static Gender[] values() {
    return $VALUE.clone();
  }
 
 //返回相同名字的枚举对象
  public static Gender valueOf(String name) {
    return Enum.valueOf(Gender.class, name);
  }
}复制代码

枚举类的书写格式:

  • 1》关键字 enum 表示该类是一个枚举类。
  • 2》该类的第一行写对象的名称,多个对象之间用逗号隔开,最后用分号结束该语句。
  • 3》其他的 类的成员 都放在对象的下面。
  • 4》如果自定义构造方法,构造方法的权限修饰符是private。
  • 5》该类可以有属性。

java枚举常见用法:https://www.cnblogs.com/singlecodeworld/p/9887926.html

values()方法不是Enum类中继承的,是编译器加的静态方法,所以,如果将enum实例向上转型为父类Enum时,values()就找不到了。
valueOf(Class<T> enumType, String name)返回带指定名称的指定枚举类型的枚举常量。

他的compareTo()是比较的枚举对象的索引差值

枚举帖子全: https://blog.youkuaiyun.com/weixin_34403693/article/details/91438731

JavaGuide 枚举:https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/basis/用好Java中的枚举真的没有那么简单.md
下面的自定义返回状态转载自上述JavaGuide的枚举文章

枚举自定义返回状态(重要)

我们在上面讲到了,我们可以通过在枚举类型中定义属性,方法和构造函数让它变得更加强大。

下面我通过一个实际的例子展示一下,当我们调用短信验证码的时候可能有几种不同的用途,我们在下面这样定义:

public enum PinType {

    REGISTER(100000, "注册使用"),
    FORGET_PASSWORD(100001, "忘记密码使用"),
    UPDATE_PHONE_NUMBER(100002, "更新手机号码使用");

    private final int code;
    private final String message;

    PinType(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    @Override
    public String toString() {
        return "PinType{" +
                "code=" + code +
                ", message='" + message + '\'' +
                '}';
    }
}

实际使用:

System.out.println(PinType.FORGET_PASSWORD.getCode());
System.out.println(PinType.FORGET_PASSWORD.getMessage());
System.out.println(PinType.FORGET_PASSWORD.toString());

Output:

100001
忘记密码使用
PinType{code=100001, message='忘记密码使用'}

clone 克隆

clone()

  • 浅拷贝:我们clone的对象和新对象不是同一对象。但是对象中的引用类型属性的引用是一样的。举例,对象a的数组属性跟克隆的aClone对象的数组属性是同一个。
  • 深拷贝:拷贝的对象及引用类型都不一样。怎么实现?就是引用类型也复制一个放进新对象里。具体看下边这个帖子

clone()拓展:https://blog.youkuaiyun.com/xinghuo0007/article/details/78896726

网络编程

1.网络:计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,实现资源共享和信息传递的计算机系统。
2.计算机网络是网状结构。
3.网络分层模型:
(1)OSI 七层模型
开放式系统互联
在这里插入图片描述
(2)TCP/IP 四层模型
在这里插入图片描述
网络三要素: ip地址,协议,端口号
(1)IP地址:
①IP地址 表示的是计算机在网络中的唯一地址。
②常见的ip地址分类:
1)Ipv4:
a.点分十进制 ,共4组,32位。分为5类。
例如: 192.168.1.1
b.127.0.0.1 网络回环地址,主机地址,等价于主机名称:localhost
IPv6:共128位,每组4个十六进制的数。通过冒号分隔
(2)信协议
①在计算机通信中,必须要遵守的规则、协议。
②常见通信协议:
1)FTP:文件传输协议。
2)http:超文本传输协议
Smtp 邮件传输协议 、pop3 邮局协议 、telnet 远程登录
(3)端口号
①标识计算机中应用程序 ,不同的软件有不同的端口号。
②端口号 从0-65535,建议用9000以后的端口。
1)Mysql 3306
2)Oracle 1521
3)Tomcat 8080

TCP三次握手,四次挥手

https://mp.weixin.qq.com/s/QlBxYrdEeEoHDsVm857-zg
三次握手:连接的时候
四次挥手:断开连接的时候

TCP和UDP对比

(1)UDP 面向无连接的 ,通过数据报包进行传输,最大传输不能超过64k,不可靠传输速度快
(2)TCP 面向连接的,通过字节流的通道进行数据传输,没有传输限制==,可靠,但是传输速度慢

InetAddress 描述ip地址的类

获取InetAddress对象方式:
getByName(String host) 根据给定的主机名获取对象
getByAddress()根据ip地址的字节数组获取当前类型对象
getLocalHost() 返回本地主机地址

InetAddress ip = InetAddress.getByName("192.168.123.123");
InetAddress ip2 = InetAddress.getLocalHost();

对象使用方法:
getHostName() 返回主机名称
getHostAddress() 返回ip地址的数字的表示形式
getAddress():获取ip地址的字节数组。

String address = ip.getHostAddress();
String name = ip.getHostName();
byte[] bytes = ip.getAddress();

UDP编程

Java提供的UDP的类:
DatagramSocket 发送端和接收端
DatagramPacket 数据报包
常用方法:
① DatagramSocket() 创建一个数据报包的端点。
② DatagramPacket(byte[] buf, int length, InetAddress address, int port)
发送端需要携带ip地址与端口号,来创建数据报包,接收可不写
注意 : address 表示目的地的电脑的ip地址
port 表示目的地的端口号。
默认数据报包大小不能超过64k。
③send(DatagramPacket p) 发送数据报包。
④ receive(DatagramPacket p) 接收数据
⑤ getLength() 返回接收或者发送的字节数组的读取的数据的长度。

UDP简单的聊天
端口1:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Chat1 {
   private static final String host1 = "10.10.18.148";
   private static final int port1 = 9000;
   private static final int port2 = 9001;
   
   public static void main(String[] args) throws IOException {

   	Scanner scanner = new Scanner(System.in);
   	// 获取Socket对象
   	DatagramSocket socket = new DatagramSocket(port2);
   	boolean flag= true;
   	FutureTask<Object> ft = new FutureTask<Object>(new Callable<Object>() {
   		@Override
   		public Object call() throws Exception {
   			while(flag){
   				//接收
   				byte[] recive = new byte[1024];
   				DatagramPacket pa1 = new DatagramPacket(recive, recive.length);
   				socket.receive(pa1);
   				int len = 0;
   				if ((len = pa1.getLength()) > 0) {
   					System.out.println(pa1.getAddress()+"-9001端口说:"+new String(recive,0,pa1.getLength()));
   				}
   			}
   			return null;
   		}
   	});
   	new Thread(ft).start();
   	
   	while (flag) {
   		System.out.println("请输入信息:");
   		String msg = scanner.nextLine();
   		if (msg.equals("下线")) {
   			break;
   		}
   		// 获取InetAdress
   		InetAddress host1Id = InetAddress.getByName(host1);
   		// 创建报
   		DatagramPacket pa = new DatagramPacket(
   				msg.getBytes(), msg.getBytes().length, host1Id,port1);
   		// 发送
   		socket.send(pa);
   		
   		
   	}
   	socket.close(); 
   	System.out.println("9000关闭");
   }
}

端口2:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Chat2 {
   private static final String host1 = "10.10.18.148";
   private static final int port1 = 9000;
   private static final int port2 = 9001;

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

   	Scanner scanner = new Scanner(System.in);
   	// 获取Socket对象
   	DatagramSocket socket = new DatagramSocket(port1);
   	boolean flag = true;

   	FutureTask<Object> ft = new FutureTask<Object>(new Callable<Object>() {
   		@Override
   		public Object call() throws Exception {
   			while (flag) {
   				// 接收
   				byte[] recive = new byte[1024];
   				DatagramPacket pa1 = new DatagramPacket(recive, recive.length);
   				socket.receive(pa1);
   				int len = 0;
   				if ((len = pa1.getLength()) > 0) {
   					System.out.println(pa1.getAddress() + "-9000端口说:" + new String(recive, 0, pa1.getLength()));
   				}
   			}
   			return null;
   		}
   	});
   	new Thread(ft).start();
   	while (flag) {
   		// 发送
   		System.out.println("请输入信息:");
   		String msg = scanner.nextLine();
   		if (msg.equals("下线")) {
   			break;
   		}
   		// 获取InetAdress
   		InetAddress host1Id = InetAddress.getByName(host1);
   		// 创建报
   		DatagramPacket pa = new DatagramPacket(msg.getBytes(), msg.getBytes().length, host1Id, port2);

   		// 发送
   		socket.send(pa);
   	}
   	socket.close();
   	System.out.println("9001关闭");
   }
}

两个基本一样,就是收发设置的端口号不一样。
为什么接收用多线程?不用多线程就必须一个发一个接,然后另一个发一个接,不能连续发连续接。
为什么用callable线程?因为callable可以抛异常。
为什么用while(flag)不直接用while(true)?因为如果用true,编译器会认为你一直循环下去,循环下边的代码执行不到,循环下边的代码就会报错。

TCP编程实例

实现客户端,服务器端聊天。版本1,用字节流。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/**
* 客户端 
*/
public class TCPClient {
   public static void main(String[] args) throws IOException {
   	// 客户端套接字,3次握手
   	Socket socket = new Socket(InetAddress.getLocalHost(), 9000);
   	// 获取输出流,向服务端传输数据
   	OutputStream outputStream = socket.getOutputStream();

   	Scanner scanner = new Scanner(System.in);
   	boolean flag = true;

   	// 因为while循环里,读和写都会阻塞,所以一个线程只能发送一次接收一次,不能连续发送或接收
   	new Thread(new Runnable() {
   		// 放出来,这个一个就够了,不用每次while循环都获取,如果在run里还需要抛一次异常
   		InputStream in = socket.getInputStream();
   		@Override
   		public void run() {
   			while (flag) {
   				// 接收消息
   				try {
   					byte[] bytes = new byte[1024];
   					int readNum = in.read(bytes);
   					System.out.println("服务端:" + new String(bytes, 0, readNum));
   				} catch (IOException e) {
   					e.printStackTrace();
   				}
   			}
   		}
   	}).start();

   	while (flag) {
   		// 向服务端发
   		System.out.println("请回复服务端:");
   		String msg = scanner.nextLine();
   		// 写数据
   		outputStream.write(msg.getBytes());

   		/*
   		 * //接收消息 InputStream in = socket.getInputStream(); byte[] bytes = new
   		 * byte[1024]; int readNum = 0; readNum = in.read(bytes);
   		 * System.out.println("服务端:" + new String(bytes, 0, readNum));
   		 */

   	}

   	// 关闭流
   	socket.close();
   }
}


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
* 服务端
*/
public class TCPServer {
   public static void main(String[] args) throws IOException {
   	// 创建服务器端套接字
   	ServerSocket socket = new ServerSocket(9000);
   	System.out.println("等待连接...");
   	// 获取客户端的套接字
   	Socket accept = socket.accept();
   	System.out.println("连接成功!");

   	Scanner scanner = new Scanner(System.in);
   	boolean flag = true;

   	// 向客户端回消息  必须在while循环之前
   	new Thread(new Runnable() {
   		OutputStream outputStream = accept.getOutputStream();

   		@Override
   		public void run() {
   			while (flag) {
   				System.out.println("请回复客户端:");
   				String msg = scanner.nextLine();
   				try {
   					outputStream.write(msg.getBytes());
   				} catch (IOException e) {
   					e.printStackTrace();
   				}
   			}
   		}
   	}).start();

   	while (flag) {
   		// 获取客户端的信息,输入
   		InputStream inputStream = accept.getInputStream();
   		byte[] bytes = new byte[1024];
   		int readNum = inputStream.read(bytes);
   		System.out.println("客户端:" + new String(bytes, 0, readNum));

   		/*
   		 * System.out.println("请回复客户端:"); String msg = scanner.nextLine(); OutputStream
   		 * outputStream = accept.getOutputStream(); outputStream.write(msg.getBytes());
   		 */
   	}

   	// 关闭服务端套接字
   	socket.close();
   }

}

用字符流传输,利用转换流,把字节流转换成字符流

实现客户端,服务器端聊天。 版本2,用字符流

很重要的一个知识点:
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
String msg = read.readLine();
跟Scanner的nextLine()一样可以获取控制台输入

package day24.tcp.study.copy;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;

/**
* 客户端
*/
public class TCPClient {
   public static void main(String[] args) throws IOException {
   	// 客户端套接字,3次握手
   	Socket socket = new Socket("10.10.18.114", 9000);
   	boolean flag = true;
   	// 因为while循环里,读和写都会阻塞,所以一个线程只能发送一次接收一次,不能连续发送或接收
   	new Thread(new Runnable() {
   		// 放出来,这个一个就够了,不用每次while循环都获取
   		InputStream in = socket.getInputStream();
   		BufferedReader reader = new BufferedReader(new InputStreamReader(in));

   		@Override
   		public void run() {
   			while (flag) {
   				// 接收消息
   				try {
   					System.out.println("服务端:" + reader.readLine());
   				} catch (IOException e) {
   					e.printStackTrace();
   				}
   			}
   		}
   	}).start();

   	
   	// 获取输出流,向服务端传输数据
   	OutputStream outputStream = socket.getOutputStream();
   	BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
   	//获取控制台输入,相当于Scanner
   	BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
   	System.out.println("可以随时给服务端发消息:");
   	while (flag) {
   		// 向服务端发
   		String msg = read.readLine();
   		if (msg.contains("exit")) {
   			break;
   		}
   		// 写数据
   		writer.write(msg);
   		writer.newLine();
   		writer.flush();

   	}

   	// 关闭流
   	socket.close();
   	System.out.println("成功退出客户端");
   }
}

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
* 服务端
*/
public class TCPServer {
   public static void main(String[] args) throws IOException {
   	// 创建服务器端套接字,服务器是9000端口,但不知道客户端的端口
   	ServerSocket socket = new ServerSocket(9000);
   	System.out.println("等待连接...");
   	// 获取客户端的套接字
   	Socket accept = socket.accept();
   	System.out.println("连接成功!");
   	boolean flag = true;

   	// 向客户端回消息  必须在while循环之前
   	new Thread(new Runnable() {
   		//字节流转字符流
   		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
   		//输入流,获取控制台输入
   		BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
   		@Override
   		public void run() {
   			System.out.println("可以随时给客户端回复消息:");
   			while (flag) {
   				try {
   					String msg = read.readLine();
   					writer.write(msg);
   					writer.newLine();
   					writer.flush();//切记要刷新
   				} catch (IOException e) {
   					e.printStackTrace();
   				}
   			}
   		}
   	}).start();

   	while (flag) {
   		// 获取客户端的信息,输入
   		BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
   		System.out.println(accept.getInetAddress().getHostName()+":" + reader.readLine());

   	}

   	// 关闭服务端套接字
   	socket.close();
   }

}

客户端向服务器传输文件
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 
 * 内容:客户端上传
 */
public class TcpClient {
	public static void main(String[] args) throws Exception {
		//1.创建套接字
		//2.创建文件输入流,读文件
		//3.创建输出流,向服务器写
		//4.关闭流
		Socket socket = new Socket(InetAddress.getLocalHost(),9000);
		
		BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
		BufferedInputStream in = new BufferedInputStream(
				new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\day19.doc")));
		
		int readNum = 0;
		byte[] bytes = new byte[1024];
		while ((readNum = in.read(bytes)) != -1) {
			out.write(bytes, 0, readNum);
			out.flush();//用?
		}
		
		
		out.close();
		in.close();
		socket.close();
	}
}

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
//服务器端
public class TcpServer {
	public static void main(String[] args) throws Exception {
		//1.创建服务器套接字
		//2.获取客户套接字
		//3.获取套接字输入流
		//4.创建文件输出流-------获取套接字输入流,返回成功信息
		//5.关闭资源
		ServerSocket serverSocket = new ServerSocket(9000);
		Socket accept = serverSocket.accept();
		System.out.println("连接成功");
		BufferedInputStream in = new BufferedInputStream(accept.getInputStream());
		BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File("file\\2.doc")));
		int readNum = 0;
		byte[] bytes = new byte[1024];
		while ((readNum = in.read(bytes)) != -1) {
			out.write(bytes, 0, readNum);
			out.flush();
		}
		System.out.println("接收成功");
		
	/*	BufferedWriter writer = new BufferedWriter(
				new OutputStreamWriter(accept.getOutputStream()));
		writer.write("服务器端已接收");
		writer.newLine();
		writer.flush();*/
		
		
		in.close();
		out.close();
//		writer.close();
		accept.close();
		serverSocket.close();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值