【Java基础学习】Java基础中容易忽略点-3

- 网络编程

- IP

/**
 * IP:定位一个节点:计算机、路由、通讯设备等
 * InetAddress:多个静态方法
 * 1、getLocalHost 返回本机
 * 2、getByName 根据域名DNS | IP地址 -->IP地址
 * 两个成员方法:
 * 1、getHostAddress 返回计算机地址
 * 2、getHostName 返回计算机名
 *
 */
public class IPTest {
	public static void main(String[] args) throws UnknownHostException {
		//使用getLocalHost方法创建InetAddress对象
		InetAddress addr=InetAddress.getLocalHost();
		System.out.println(addr.getHostAddress());
		System.out.println(addr.getHostName());//输出计算机名
		
		//根据域名得到InetAddress对象
		addr=InetAddress.getByName("www.baidu.com");
		System.out.println(addr.getHostAddress());//36.152.44.95
		System.out.println(addr.getHostName());//输出计算机名
		
		//根据ip得到InetAddress对象
		addr=InetAddress.getByName("36.152.44.95");
		System.out.println(addr.getHostAddress());
		System.out.println(addr.getHostName());//输出的是IP而不是域名。因为这个IP地址不存在或DNS不允许进行IP地址和域名的映射,该方法就直接返回IP地址
	}
}

- PORT

在这里插入图片描述

  • 区分软件
  • 2个字节,0~65535
  • 不同协议端口之间不影响,同一个协议内端口不能重复
  • 建议使用端口越大越好,1024以上的
/**
 * 端口
 * 1、区分软件
 * 2、2个字节,0~65535
 * 3、UDP TCP独立,同一个协议下端口不能冲突
 * 4、定义端口 越大越好
 * InetSocketAddress:父类SocketAddress
 * 1、构造器
 * new InetSocketAddress(“地址/域名”,端口)
 * 2、方法
 * getAddress
 * getPort
 * getHostName 一般通过getAddress获取
 *
 */
public class PortTest {
	public static void main(String[] args) {
		//包含端口
		InetSocketAddress socketAddress1=new InetSocketAddress("127.0.0.1",8080);
		InetSocketAddress socketAddress2=new InetSocketAddress("localhost",9000);
		System.out.println(socketAddress1.getHostName());
		System.out.println(socketAddress2.getAddress());
		System.out.println(socketAddress2.getPort());
	}
}

- URL

在这里插入图片描述
基本用法

/**
 * URL:统一资源定位器 互联网的三大基石之一(HTTP html),区分资源
 * 1、协议
 * 2、域名或计算机名
 * 3、端口 http默认80
 * 4、请求资源
 * 例如:http://www.baidu.com:80/index.html?uname=user&age=18#a
 *
 */
public class URLTest01 {
	public static void main(String[] args) throws MalformedURLException {
		URL url=new URL("http://www.baidu.com:80/index.html?uname=user&age=18#a");
		//获取四个值
		System.out.println("协议:"+url.getProtocol());
		System.out.println("域名或IP:"+url.getHost());
		System.out.println("端口:"+url.getPort());
		System.out.println("请求资源:"+url.getFile());
		System.out.println("请求资源:"+url.getPath());
		
		//参数
		System.out.println("参数:"+url.getQuery());
		//锚点
		System.out.println("锚点:"+url.getRef());
		
	}
}

- 爬虫原理

1、URL
2、下载资源
3、分析资源—正则表达式
4、数据抽取 清洗 存储等

public class SpiderTest01 {
	public static void test01() throws Exception {
		// 获取URL
		URL url = new URL("https://www.jd.com");
		// 下载资源
		InputStream is = url.openStream();
		// 分析
		BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
		BufferedWriter bw = new BufferedWriter(new FileWriter("jd.txt"));
		String msg = null;
		while ((msg = br.readLine()) != null) {
			System.out.println(msg);
			bw.write(msg);
			bw.newLine();
		}
		bw.flush();
		br.close();
		// 处理……
	}

	// 模拟浏览器
	public static void test02() throws Exception {
		// 获取URL
		URL url = new URL("https://www.dianping.com");
		// 下载资源
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		//浏览器打开网址,F12获取
		conn.setRequestProperty("User-Agent",
				"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36");
		// 分析
		BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
		BufferedWriter bw = new BufferedWriter(new FileWriter("dianping.txt"));
		String msg = null;
		while ((msg = br.readLine()) != null) {
			System.out.println(msg);
			bw.write(msg);
			bw.newLine();
		}
		bw.flush();
		br.close();
		// 处理……
	}

	public static void main(String[] args) throws Exception {
		test02();
	}
}

- 传输协议

传输层协议
1、TCP:面向连接、点到点通讯、高可靠性、占用系统资源多,效率低。应用:HTTP、ftp、smtp
2、UDP:非面向连接,传输不可靠,可能丢失、发送不管接受方是否准备好,也不管接收方是否收到、可以广播发送、开销小。应用:DNS、SNMP
应用层与传输层通过Socket通讯
在这里插入图片描述

- UDP编程

基本的流程:

发送方:
1、使用DatagramSocket 指定端口创建接收端
2、准备数据,一定转成字节数组
3、封装成DatagramPacket,需要指定目的地IP+PORT
4、发送包裹,send(DatagramPacket p)
5、释放资源

/**
 * 发送端
 * 1、使用DatagramSocket 指定端口创建接收端
 * 2、准备数据,一定转成字节数组
 * 3、封装成DatagramPacket,需要指定目的地IP+PORT
 * 4、发送包裹,send(DatagramPacket p) 
 * 5、释放资源
 *
 */
public class UDPClient {
	public static void main(String[] args) throws IOException {
		System.out.println("发送方启动中…………");
		// 1、使用DatagramSocket 指定端口创建接收端
		DatagramSocket client=new DatagramSocket(8888);
		// 2、准备数据,一定转成字节数组
		String data="努力学习!!!";
		byte[] datas=data.getBytes();
		// 3、封装成DatagramPacket,需要指定目的地IP+PORT
		DatagramPacket packet=new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999));
		// 4、发送包裹,send(DatagramPacket p)
		client.send(packet);
		// 5、释放资源
		client.close();
	}
}

接收方:
1、使用DatagramSocket 指定端口创建接收端
2、准备容器,封装成成DatagramPacket
3、阻塞式接收方法 receive(DatagramPacket p)
4、分析数据
byte[] getData()
int getLength()
5、释放资源

/**
 * 接收端:
 * 1、使用DatagramSocket 指定端口创建接收端
 * 2、准备容器,封装成成DatagramPacket
 * 3、阻塞式接收方法 receive(DatagramPacket p)
 * 4、分析数据 
 * byte[] getData() 
 * int    getLength()
 * 5、释放资源
 *
 */
public class UDPServer {
	public static void main(String[] args) throws IOException {
		System.out.println("接收端启动中…………");
		//1、使用DatagramSocket 指定端口创建接收端
		DatagramSocket server=new DatagramSocket(9999);
		//2、准备容器,封装成成DatagramPacket
		byte[] container=new byte[1024];//最大接收60k
		DatagramPacket packet=new DatagramPacket(container,0,container.length);
		//3、阻塞式接收方法 receive(DatagramPacket p)
		server.receive(packet);//阻塞式
		//4、分析数据 
		byte[] datas=packet.getData();
		int len=packet.getLength();
		System.out.println(new String(datas,0,len));
		//5、释放资源
		server.close();
	}
}

与IO流对接:

只需改变发送方步骤中2,接收方步骤中4
1、基本类型:使用数据流 转成字节数组
2、引用类型:使用对象流 转成字节数组
3、文件:FileInput ByteArrayOutputStren 转成字节数组

应用:在线咨询系统:

TalkSend:

public class TalkSend implements Runnable {
	private DatagramSocket client;
	private BufferedReader reader;
	private String toIP;
	private int toPort;

	public TalkSend(int port,String toIP,int toPort) {
		this.toIP=toIP;
		this.toPort=toPort;
		try {
			client = new DatagramSocket(port);
			reader = new BufferedReader(new InputStreamReader(System.in));
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		while (true) {
			String data;
			try {
				data = reader.readLine();
				byte[] datas = data.getBytes();
				// 3、封装成DatagramPacket,需要指定目的地IP+PORT
				DatagramPacket packet = new DatagramPacket(datas, 0, datas.length,
						new InetSocketAddress(toIP, toPort));
				// 4、发送包裹,send(DatagramPacket p)
				client.send(packet);
				if (data.equals("bye")) {
					break;
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		// 5、释放资源
		client.close();

	}
}

TalkReceive:

public class TalkReceive implements Runnable{
	private DatagramSocket server;
	private String from;
	public TalkReceive(int port,String from) {
		this.from=from;
		try {
			server=new DatagramSocket(port);
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void run() {
		while (true) {
			// 2、准备容器,封装成成DatagramPacket
			byte[] container = new byte[1024];// 最大接收60k
			DatagramPacket packet = new DatagramPacket(container, 0, container.length);
			// 3、阻塞式接收方法 receive(DatagramPacket p)
			try {
				server.receive(packet);// 阻塞式
				// 4、分析数据
				byte[] datas = packet.getData();
				int len = packet.getLength();
				String data=new String(datas, 0, len);
				System.out.println(from+":"+data);
				if(data.equals("bye")) {
					break;
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		//5、释放资源
		server.close();
		
	}
}

TalkTeacher :

public class TalkTeacher {
	public static void main(String[] args) {
		new Thread(new TalkReceive(9999,"学生")).start();//接收
		new Thread(new TalkSend(5555,"localhost",8888)).start();//发送
	}
}

TalkStudent :

public class TalkStudent {
	public static void main(String[] args) {
		new Thread(new TalkSend(6666,"localhost",9999)).start();//发送
		new Thread(new TalkReceive(8888,"老师")).start();//接收
	}
}

- TCP编程

在这里插入图片描述

- 基本流程

Clinet:
1、建立连接:使用Socket创建客户端+服务器地址端口
2、操作:输入输出流相关操作
3、释放资源

/**
 * 熟悉流程
 * 创建客户端
 * 1、建立连接:使用Socket创建客户端+服务器地址端口
 * 2、操作:输入输出流相关操作
 * 3、释放资源
 *
 */
public class Client {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Client……………");
		// 1、建立连接:使用Socket创建客户端+服务器地址端口
		Socket client=new Socket("localhost",8888);
		// 2、操作:输入输出流相关操作
		DataOutputStream dos=new DataOutputStream(client.getOutputStream());
		String data="hello";
		dos.writeUTF(data);
		dos.flush();
		// 3、释放资源
		dos.close();
		client.close();
	}
}

Server:
1、指定端口,使用ServerSocket
2、阻塞式等待连接accept
3、操作:输入输出流相关操作
4、释放资源
Server 在这里插入代码片

public class Server {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Server……………");
		// 1、指定端口,使用ServerSocket
		ServerSocket server=new ServerSocket(8888);
		// 2、阻塞式等待连接accept
		Socket client=server.accept();
		System.out.println("一个客户端建立了连接……");
		// 3、操作:输入输出流相关操作
		DataInputStream dis=new DataInputStream(client.getInputStream());
		String data=dis.readUTF();
		System.out.println(data);
		// 4、释放资源
		dis.close();
		client.close();
	}
}

- 与IO流对接-文件拷贝

FileServer

public class FileServer {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Server……………");
		// 1、指定端口,使用ServerSocket
		ServerSocket server=new ServerSocket(8888);
		// 2、阻塞式等待连接accept
		Socket client=server.accept();
		System.out.println("一个客户端建立了连接……");
		// 3、操作:文件拷贝
		InputStream is=new BufferedInputStream(client.getInputStream());
		OutputStream os=new BufferedOutputStream(new FileOutputStream("IO-TCP.png"));
		byte[] flush=new byte[1024];
		int len=-1;
		while((len=is.read(flush))!=-1) {
			os.write(flush, 0, len);
		}
		os.flush();
		
		// 4、释放资源
		os.close();
		is.close();
		client.close();
	}
}

FileClient

public class FileClient {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Client……………");
		// 1、建立连接:使用Socket创建客户端+服务器地址端口
		Socket client=new Socket("localhost",8888);
		// 2、操作:拷贝
		InputStream is=new BufferedInputStream(new FileInputStream("src/IO.png"));
		OutputStream os=new BufferedOutputStream(client.getOutputStream());
		byte[] flush=new byte[1024];
		int len=-1;
		while((len=is.read(flush))!=-1) {
			os.write(flush, 0, len);
		}
		os.flush();
		// 3、释放资源
		os.close();
		is.close();
		client.close();
	}
}

- 模拟登录 多个客户端请求

LoginMultiClient

public class LoginMultiClient {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Client……………");
		// 1、建立连接:使用Socket创建客户端+服务器地址端口
		Socket client = new Socket("localhost", 8888);
		// 2、操作:输入输出流相关操作 先请求后响应
		new Send(client).send();
		// 接收
		new Receive(client).receive();

		// 3、释放资源

		client.close();
	}

	static class Send {
		private Socket client;
		private DataOutputStream dos;
		private BufferedReader console;
		private String msg;

		public Send(Socket client) {
			console = new BufferedReader(new InputStreamReader(System.in));
			this.msg = init();
			this.client = client;
			try {
				dos = new DataOutputStream(client.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
				try {
					dos.close();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}

		private String init() {
			try {
				System.out.print("请输入用户名:");
				String uname = console.readLine();
				System.out.print("请输入密码:");
				String upwd = console.readLine();
				return "uname=" + uname + "&" + "upwd:" + upwd;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return "";
		}

		public void send() {
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}

	static class Receive {
		private Socket client;
		private DataInputStream dis;

		public Receive(Socket client) {
			this.client = client;

			try {
				dis = new DataInputStream(client.getInputStream());
			} catch (IOException e) {
				e.printStackTrace();
				try {
					dis.close();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}

		}

		public void receive() {
			String result;
			try {
				result = dis.readUTF();
				System.out.println(result);
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}
}

LoginMultiServer

public class LoginMultiServer {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Server……………");
		// 1、指定端口,使用ServerSocket
		ServerSocket server = new ServerSocket(8888);
		boolean isRunning = true;
		// 2、阻塞式等待连接accept
		while (isRunning) {
			Socket client = server.accept();
			System.out.println("一个客户端建立了连接……");
			new Thread(new Channel(client)).start();
		}

		server.close();
	}
	//一个channel就代表一个客户端	
	static class Channel implements Runnable {
		private Socket client;

		// 输入流
		private DataInputStream dis;
		// 输出流
		private DataOutputStream dos;

		public Channel(Socket client) {
			this.client = client;
			try {
				dis = new DataInputStream(client.getInputStream());
				// 输出
				dos = new DataOutputStream(client.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
				release();
			}
		}

		// 释放资源
		private void release() {
			try {
				if (null != dos) {
					dos.close();
				}

			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (null != dis) {
					dis.close();
				}

			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (null != client) {
					client.close();
				}

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

		// 接收数据
		private String receive() {
			String datas = "";
			try {
				datas = dis.readUTF();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return datas;
		}

		// 发送数据
		private void send(String msg) {
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		@Override
		public void run() {
			// 3、操作:输入输出流相关操作

			String uname = "";
			String upwd = "";
			// 分析
			String[] dataArray = receive().split("&");
			for (String info : dataArray) {
				String[] userInfo = info.split("=");
				if (userInfo[0].equals("uname")) {
					System.out.println("你的用户名为:" + userInfo[1]);
					uname = userInfo[1];
				} else if (userInfo[0].equals("upwd")) {
					System.out.println("你的密码为:" + userInfo[1]);
					upwd = userInfo[1];
				}
			}

			if (uname.equals("study") && upwd.equals("123456")) {
				send("登录成功,欢迎回来");
			} else {// 失败
				send("用户名或密码错误");
			}
			// 4、释放资源
			release();
		}

	}

}

- 在线聊天室 封装版

Receive

/**
 * 使用多线程封装了接收端
 * 1、接收消息
 * 2、释放资源
 * 3、重写run
 *
 */
public class Receive implements Runnable {
	private DataInputStream dis;
	private Socket client;
	private boolean isRunning;

	public Receive(Socket client) {
		this.client = client;
		try {
			dis = new DataInputStream(client.getInputStream());
			this.isRunning = true;
		} catch (IOException e) {
			System.out.println("Receive error");
			release();
		}
	}

	// 接收消息
	private String receive() {
		String msg = "";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			System.out.println("Receive:receive error");
			release();
		}
		return msg;
	}

	@Override
	public void run() {
		while(isRunning) {
			String msg=receive();
			if(!msg.equals("")) {
				System.out.println(msg);
			}
			
		}

	}

	// 释放资源
	private void release() {
		this.isRunning = false;
		StudyUtils.close(dis, client);
	}
}

Send

/**
 * 使用多线程封装了发送端
 * 1、发送消息
 * 2、从控制台获取消息
 * 3、释放资源
 * 4、重写run
 *
 */
public class Send implements Runnable {
	private BufferedReader console;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;

	public Send(Socket client) {
		this.client = client;
		console = new BufferedReader(new InputStreamReader(System.in));
		try {
			dos = new DataOutputStream(client.getOutputStream());
			this.isRunning=true;
		} catch (IOException e) {
			System.out.println("Send error");
			release();
		}
	}

	@Override
	public void run() {
		while (isRunning) {
			String msg = getStrFromConsole();
			if (!msg.equals("")) {
				send(msg);
			}
		}

	}

	// 发送消息
	private void send(String msg) {
		try {
			dos.writeUTF(msg);
			dos.flush();
		} catch (IOException e) {
			System.out.println("Send:send error");
			release();
		}
	}

	/**
	 * 从控制台获取消息
	 * 
	 * @return
	 */
	private String getStrFromConsole() {
		try {
			return console.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}

	// 释放资源
	private void release() {
		this.isRunning = false;
		StudyUtils.close(dos, client);
	}
}

TMultiClient

/**
 * 在线聊天室:客户端
 * 目标:封装 使用多线程实现多个客户可以正常收发多条信息
 *
 */
public class TMultiClient {
	public static void main(String[] args) throws Exception {
		System.out.println("……………Client……………");
		//1、建立连接:使用Socket创建客户端+服务的地址和端口
		Socket client=new Socket("localhost",8888);
		//2、客户端发送消息
		new Thread(new Send(client)).start();
		//3、客户端获取消息
		new Thread(new Receive(client)).start();
	}
}

TMultiChat

/**
 * 在线聊天室:服务器 
 * 目标:封装 使用多线程实现多个客户可以正常收发多条信息
 * 
 *
 */
public class TMultiChat {
	public static void main(String[] args) throws IOException {
		System.out.println("……………Server……………");
		// 1、指定端口,使用ServerSocket
		ServerSocket server = new ServerSocket(8888);
		// 2、阻塞式等待连接accept
		while (true) {
			Socket client=server.accept();
			System.out.println("一个客户端建立了连接");
			new Thread(new Channel(client)).start();

		}

	}
	
	//一个客户端代表一个channel
	static class Channel implements Runnable{
		private DataInputStream dis;
		private DataOutputStream dos;
		private Socket client;
		private boolean isRunning;
		public Channel(Socket client) {
			this.client=client;
			try {
				dis = new DataInputStream(client.getInputStream());
				dos = new DataOutputStream(client.getOutputStream());
				isRunning = true;
			} catch (IOException e) {
				release();
			}
		}
		
		//接收消息
		private String receive() {
			String msg="";
			try {
				msg=dis.readUTF();
			} catch (IOException e) {
				System.out.println("receive error");
				release();
			}
			return msg;
		}
		//发送消息
		private void send(String msg) {
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				System.out.println("send error");
				release();
			}
		}
		//释放资源
		private void release() {
			this.isRunning=false;
			StudyUtils.close(dis,dos,client);
		}
		
		@Override
		public void run() {
			while(isRunning) {
				String msg=receive();
				if(!msg.equals("")) {
					send(msg);
				}
			}
		}
		
	}
}

- 在线聊天室 群聊+私聊

Receive

public class Receive implements Runnable {
	private DataInputStream dis;
	private Socket client;
	private boolean isRunning;

	public Receive(Socket client) {
		this.client = client;
		try {
			dis = new DataInputStream(client.getInputStream());
			this.isRunning = true;
		} catch (IOException e) {
			System.out.println("Receive error");
			release();
		}
	}

	// 接收消息
	private String receive() {
		String msg = "";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			System.out.println("Receive:receive error");
			release();
		}
		return msg;
	}

	@Override
	public void run() {
		while(isRunning) {
			String msg=receive();
			if(!msg.equals("")) {
				System.out.println(msg);
			}
			
		}

	}

	// 释放资源
	private void release() {
		this.isRunning = false;
		StudyUtils.close(dis, client);
	}
}

Send

public class Send implements Runnable {
	private BufferedReader console;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;
	private String name;

	public Send(Socket client,String name) {
		this.client = client;
		console = new BufferedReader(new InputStreamReader(System.in));
		this.isRunning=true;
		this.name=name;
		try {
			dos = new DataOutputStream(client.getOutputStream());
			//发送名称
			send(name);
		} catch (IOException e) {
			System.out.println("Send error");
			release();
		}
	}

	@Override
	public void run() {
		while (isRunning) {
			String msg = getStrFromConsole();
			if (!msg.equals("")) {
				send(msg);
			}
		}

	}

	// 发送消息
	private void send(String msg) {
		try {
			dos.writeUTF(msg);
			dos.flush();
		} catch (IOException e) {
			System.out.println("Send:send error");
			release();
		}
	}

	/**
	 * 从控制台获取消息
	 * 
	 * @return
	 */
	private String getStrFromConsole() {
		try {
			return console.readLine();
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("getStrFromConsole error");
		}
		return "";
	}

	// 释放资源
	private void release() {
		this.isRunning = false;
		StudyUtils.close(dos, client);
	}
}

Chat

public class Chat {

	private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<Channel>();

	public static void main(String[] args) throws IOException {
		System.out.println("……………Server……………");
		// 1、指定端口,使用ServerSocket
		ServerSocket server = new ServerSocket(8888);
		// 2、阻塞式等待连接accept
		while (true) {
			Socket client = server.accept();
			System.out.println("一个客户端建立了连接");
			Channel c = new Channel(client);
			all.add(c);// 管理所有的成员
			new Thread(c).start();

		}

	}

	// 一个客户端代表一个channel
	static class Channel implements Runnable {
		private DataInputStream dis;
		private DataOutputStream dos;
		private Socket client;
		private boolean isRunning;
		private String name;

		public Channel(Socket client) {
			this.client = client;
			try {
				dis = new DataInputStream(client.getInputStream());
				dos = new DataOutputStream(client.getOutputStream());
				isRunning = true;
				// 获取名称
				name = receive();
				// 欢迎你的到来
				this.send("欢迎你的到来");
				sendOthers(this.name + "来到了Study聊天室", true);
			} catch (IOException e) {
				release();
			}
		}

		// 接收消息
		private String receive() {
			String msg = "";
			try {
				msg = dis.readUTF();
			} catch (IOException e) {
				System.out.println("receive error");
				release();
			}
			return msg;
		}

		// 发送消息
		private void send(String msg) {
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				System.out.println("send error");
				release();
			}
		}

		/**
		 * 群聊 :获取自己的消息发给其他人
		 * 私聊:约定数据格式:@xxx:msg
		 * @param msg
		 */
		private void sendOthers(String msg,boolean isSys) {
			boolean isPrivate=msg.startsWith("@");
			if(isPrivate) {//私聊
				//获取目标和数据
				String data=msg.substring(1, msg.length());
				String[] datas=data.split(":");
				String targetName=datas[0];
				msg=datas[1];
				for(Channel other : all) {
					if(other.name.equals(targetName)) {//目标
						other.send("["+this.name+" 悄悄地说]"+msg);
						break;
					}
				}
			}else {//群聊 或系统消息
				for (Channel other : all) {
					if (other == this)
						continue;
					if(!isSys) {
						other.send("["+this.name+"]"+msg);//群聊消息
					}else {
						other.send(msg);//系统消息
					}
				}
			}
			
		}

		// 释放资源
		private void release() {
			this.isRunning = false;
			StudyUtils.close(dis, dos, client);
			// 退出
			all.remove(this);
			sendOthers(this.name + "离开了群聊……", true);
		}

		@Override
		public void run() {
			while (isRunning) {
				String msg = receive();
				if (!msg.equals("")) {
					// send(msg);
					sendOthers(msg, false);
				}
			}
		}

	}
}

Client

public class Client {
	public static void main(String[] args) {
		System.out.println("……………Client……………");
		BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入用户名:");
		String name="";
		try {
			name = br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("br.readLine error");
		}
		//1、建立连接:使用Socket创建客户端+服务的地址和端口
		Socket client=null;
		try {
			client = new Socket("localhost",8888);
		} catch (UnknownHostException e) {
			e.printStackTrace();
			System.out.println("new Socket error");
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("new Socket error");
		}
		//2、客户端发送消息
		new Thread(new Send(client,name)).start();
		//3、客户端获取消息
		new Thread(new Receive(client)).start();
	}
}

StudyUtils

public class StudyUtils {
	/**
	 * 释放资源
	 */
	public static void close(Closeable... targets) {
		for(Closeable target:targets) {
			try {
				if(null!=target) {
					target.close();
				}
			}catch(Exception e){
				
			}
		}
	}
}

- 总结

1、定位:
如何定位一台机器?IP —>InetAddress
如何定位机器上的软件?PORT----->InetSocketAddress
如何定位软件上的资源?URL------->Url
2、底层传输协议:
TCP:面向连接,安全可靠,性能低,底层使用IO字节流
服务端:ServerSocket :accept()
客户端:Socket
UDP:非面向连接,性能高
发送/接收:DatagramSocket:send() reveive()
数据:DatagramPacket
基于以上协议可以做Socket编程,Socket是传输层与应用层的接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值