10.网络编程

在这里插入图片描述
ip:定位计算机
port:定位软件
url:定位软件里面的每一份资源

InetAddress:
在这里插入图片描述

package com.sheye.location;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * ip:定位一个节点
 * @author Sheye
 *
 */
public class IpTest {

	public static void main(String[] args) throws UnknownHostException {
		//使用getLocalHost方法创建InetAddress对象
		InetAddress addr= InetAddress.getLocalHost();
		System.out.println(addr.getHostAddress()); //返回:192.168.xxx.x
		System.out.println(addr.getHostName()); //输出计算机名
		
		//根据域名得到InetAddress对象
		addr= InetAddress.getByName("www.163.com");
		System.out.println(addr.getHostAddress()); //返回163服务器的ip:61.135.253.15
		System.out.println(addr.getHostName()); //输出:www.163.com
		
		//根据ip得到InetAddress对象
		addr= InetAddress.getByName("61.135.253.15");
		System.out.println(addr.getHostAddress()); //返回163服务器的ip:61.135.253.15
		System.out.println(addr.getHostName()); //输出ip而不是域名。如果这个IP地址不存在或DNS服务器不允许进行IP地址和域名的映射,getHostName方法就直接返回这个IP地址。
	}
}

端口;
在这里插入图片描述
InetSocketAddress(ip+port=socket):
*父类为SocketAddress,api中形参类型写SocketAddress,一般指InetSocketAddress
在这里插入图片描述

package com.sheye.location;

import java.net.InetSocketAddress;

/**
 * 端口
 * 1.区分软件
 * 2.2个字节 0-65535 udp tcp
 * 3.同一个协议端口不能冲突
 * 4.定义端口越大越好
 * 
 * 1.构造器
 * new InetSocketAddress(ip|域名,端口);
 * 1.方法
 * getHostName
 * getAddress--返回的InetAddress-->输出localhost/127.0.0.1 hostname/ip
 * getPort
 * @author Sheye
 *
 */
public class PortTest {

	public static void main(String[] args) {
		//包含端口 父类为SocketAddress
		InetSocketAddress socketAddress= new InetSocketAddress("127.0.0.1",8080);
		InetSocketAddress socketAddress2 = new InetSocketAddress("localhost",9000);
		System.out.println(socketAddress.getHostName());
		//public final InetAddress getAddress()
		System.out.println(socketAddress2.getAddress());
		System.out.println(socketAddress2.getAddress().getHostName());
		System.out.println(socketAddress.getPort());
	}
}

URL:
在这里插入图片描述
url的基础使用:

package com.sheye.location;

import java.net.MalformedURLException;
import java.net.URL;

/**
 * URL:统一资源定位器
 * 1.协议
 * 2.域名,计算机
 * 3.端口:默认80
 * 4.请求资源
 * @author Sheye
 *
 */
public class URLTest01 {

	public static void main(String[] args) throws MalformedURLException {
		URL u = new URL("http://www.baidu.con:80/index.html#aa?cansu=shsxt");
		System.out.println("获取与此url关联的协议的默认端口:"+u.getDefaultPort());
		System.out.println("getFile:"+u.getFile()); //端口号后面的内容
		System.out.println("主机名:"+u.getHost()); //www.baidu.com
		System.out.println("路径:"+u.getPath()); //端口号后,参数前的内容
		System.out.println("端口:"+u.getPort()); //存在返回80.否则返回-1
		System.out.println("协议:"+u.getProtocol());
		System.out.println("参数部分:"+u.getQuery());
		System.out.println("锚点:"+u.getRef());
		u = new URL("http://www.abc.com/aa/");
		URL u2 = new URL(u,"2.html"); //相对路径构建url对象
		System.out.println(u2.toString()); //http://www.abc.com/aa/2.html
	}
}

在这里插入图片描述
网络爬虫的原理01:

package com.sheye.location;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * 网络爬虫的原理
 * @author Sheye
 *
 */
public class SpiderTest02 {

	public static void main(String[] args) throws Exception {
		//获取url
		URL url = new URL("https://www.jd.com");
		//下载资源
		InputStream is = url.openStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String msg = null;
		while (null!=(msg=br.readLine())) {
			System.out.println(msg);
		}
		br.close();
		//分析
		//处理
	}
}

网络爬虫的原理02:

package com.sheye.location;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * 网络爬虫得原理+模拟浏览器
 * @author Sheye
 *
 */
public class SpiderTest02 {

	public static void main(String[] args) throws Exception {
		//获取url
		URL url = new URL("https://www.dianping.com");
		//下载资源
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0");
		BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
		String msg = null;
		while (null!=(msg=br.readLine())) {
			System.out.println(msg);
		}
		br.close();
		//分析
		//处理
	}
}

Socket是应用层向传输层开的一个小口:
在这里插入图片描述
UDP编程:
在这里插入图片描述
UDP基本步骤:
服务端:

package com.sheye.udp;

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

/**
 * 接收端(服务器进行接受):
 * 1.使用DatagramSocket 指定端口 创建接受端
 * 2.准备容器 封装成DatagramPacket包裹
 * 3.阻塞式接收包裹receive(DatagramPacket p)
 * 4.分析数据
 * 		byte[] getData()
 * 		int getLength()
 * 5.释放资源
 * @author Administrator
 *
 */
public class UpdServer {

	public static void main(String[] args) throws Exception {
		System.out.println("服务端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建接受端
		DatagramSocket server = new DatagramSocket(9999);
		//2.准备容器 封装成DatagramPacket包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		//3.阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);	//阻塞式接
		//4.分析数据
		byte[] datas = packet.getData();
		System.out.println(new String(datas,0,datas.length));
		//5.释放资源
		server.close();
	}
}

客户端:

package com.sheye.udp;

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

/**
 * 发送端:
 * 1.使用DatagramSocket 指定端口 创建发送端
 * 2.准备数据 一定转成字节数组
 * 3.封装成DatagramPacket包裹	需要指定目的地
 * 4.发送包裹send(DatagramPacket p)
 * 5.释放资源
 * @author Administrator
 *从8888端口发送到9999端口
 */
public class UdpClient {

	public static void main(String[] args) throws Exception {
		System.out.println("客户端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		//2.准备数据 一定转成字节数组
		String msg = "我是一只小鸭子";
		byte[] datas = msg.getBytes();
		//3.封装成DatagramPacket包裹	需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
				new InetSocketAddress("localhost",9999));
		//4.发送包裹send(DatagramPacket p)
		client.send(packet);
		//5.释放资源
		client.close();
	}
}

UDP上传文件:
1.基本数据类型进行传输:
接收端

package com.sheye.udp;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * 基本数据类型:接收端(服务器进行接受)
 * 1.使用DatagramSocket 指定端口 创建接受端
 * 2.准备容器 封装成DatagramPacket包裹
 * 3.阻塞式接收包裹receive(DatagramPacket p)
 * 4.分析数据	将字节数组转化为对应的基本数据类型
 * 		byte[] getData()
 * 		int getLength()
 * 5.释放资源
 * @author Administrator
 *
 */
public class UpdTypeServer {

	public static void main(String[] args) throws Exception {
		System.out.println("服务端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建接受端
		DatagramSocket server = new DatagramSocket(9999);
		//2.准备容器 封装成DatagramPacket包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		//3.阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);	//阻塞式接
		//4.分析数据 将字节数组转化为对应的基本数据类型
		byte[] datas = packet.getData();
		int len = packet.getLength();
		DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
		String msg = dis.readUTF();
		int age = dis.readInt();
		boolean flag = dis.readBoolean();
		char ch = dis.readChar();
		
		System.out.println(msg+":"+flag);
		//5.释放资源
		server.close();
	}
}

发送端:

package com.sheye.udp;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
 * 同一个协议下端口不允许冲突
 * 发送端:
 * 1.使用DatagramSocket 指定端口 创建发送端
 * 2.将基本数据类型 转成字节数组
 * 3.封装成DatagramPacket包裹	需要指定目的地
 * 4.发送包裹send(DatagramPacket p)
 * 5.释放资源
 * 
 * @author Administrator
 *从8888端口发送到9999端口
 */
public class UdpTypeClient {

	public static void main(String[] args) throws Exception {
		System.out.println("客户端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		//2.准备数据 将基本数据类型 转成字节数组
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
		//操作数据类型+数据
		dos.writeUTF("我是一只小鸭");
		dos.writeInt(12);
		dos.writeBoolean(false);
		dos.writeChar('a');
		dos.flush();
		byte[] datas = baos.toByteArray();
		System.out.println(datas.length);
		//3.封装成DatagramPacket包裹	需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
				new InetSocketAddress("localhost",9999));
		//4.发送包裹send(DatagramPacket p)
		client.send(packet);
		//5.释放资源
		client.close();
	}
}

2.引用数据类型进行传输:
发送端:

package com.sheye.udp;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Date;

/**
 * 同一个协议下端口不允许冲突
 * 操作引用数据类型:发送端:
 * 1.使用DatagramSocket 指定端口 创建发送端
 * 2.将基本数据类型 转成字节数组
 * 3.封装成DatagramPacket包裹	需要指定目的地
 * 4.发送包裹send(DatagramPacket p)
 * 5.释放资源
 * 
 * @author Administrator
 *从8888端口发送到9999端口
 */
public class UdpObjClient {

	public static void main(String[] args) throws Exception {
		System.out.println("客户端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		//2.准备数据 将基本数据类型 转成字节数组
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(baos));
		
		oos.writeObject("我想你或许才是那个怪胎罢了\r\n");
		oos.writeObject(new Date());
		oos.writeObject(new Emp("猴子先生",12.00));
		oos.flush();//不flush流会出现java.io.EOFException错误
		oos.close();
		
		byte[] datas = baos.toByteArray();
		
		
		//3.封装成DatagramPacket包裹	需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
				new InetSocketAddress("localhost",9999));
		//4.发送包裹send(DatagramPacket p)
		client.send(packet);
		//5.释放资源
		client.close();
	}
}

class Emp implements Serializable{
	//数据不需要存储下来,该数据不需要序列化
	private transient String name;
	private double salary;
	
	
	public Emp() {
		super();
	}


	public Emp(String name, double salary) {
		super();
		this.name = name;
		this.salary = salary;
	}


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	public double getSalary() {
		return salary;
	}


	public void setSalary(double salary) {
		this.salary = salary;
	}


	@Override
	public String toString() {
		return "Emp [name=" + name + ", salary=" + salary + "]";
	}	
}

接收端:

package com.sheye.udp;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * 操作引用数据类型:接收端(服务器进行接受)
 * 1.使用DatagramSocket 指定端口 创建接受端
 * 2.准备容器 封装成DatagramPacket包裹
 * 3.阻塞式接收包裹receive(DatagramPacket p)
 * 4.分析数据	将字节数组转化为对应的基本数据类型
 * 		byte[] getData()
 * 		int getLength()
 * 5.释放资源
 * @author Administrator
 *
 */
public class UpdObjServer {

	public static void main(String[] args) throws Exception {
		System.out.println("服务端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建接受端
		DatagramSocket server = new DatagramSocket(9999);
		//2.准备容器 封装成DatagramPacket包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		//3.阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);	//阻塞式接
		//4.分析数据 将字节数组转化为对应的基本数据类型
		byte[] datas = packet.getData();
		int len = packet.getLength();
		ByteArrayInputStream bais = new ByteArrayInputStream(datas);
		ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(bais));
		
		Object str = ois.readObject();
		Object date = ois.readObject();
		Object emp = ois.readObject();	
		
		System.out.println(str+":"+date+":"+emp);

		
		//5.释放资源
		server.close();

	}
}

3.文件的上传和存储
IOUtils:


package com.sheye.udp;
import java.io.*;

public class IOUtils {

    //图片读取到字节数组
    public static byte[] fileToByteArray(String filePath){
        //创建源
        File src = new File(filePath);
        byte[] dest=null;
        InputStream is=null;
        ByteArrayOutputStream baos=null;
        try {
            byte[] flush = new byte[1024*10];
            is = new FileInputStream(src);
            baos = new ByteArrayOutputStream();
            int len;
            while ((len=is.read(flush))!=-1){
                baos.write(flush,0,len);
            }
            baos.flush();
            dest=baos.toByteArray();
            return dest;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    //字节数组写出到图片
    public static void byteArrayToFile(byte[] src,String filePath){
        File dest = new File(filePath);
        OutputStream os =null;
        ByteArrayInputStream bais = null;
        byte[] flush=new byte[1024*10];
        try {
            os = new  FileOutputStream(dest);
            bais = new ByteArrayInputStream(src);
            int len;
            while ((len=bais.read(flush))!=-1){
                os.write(flush,0,flush.length);
            }
            os.flush();

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

    }
}

文件上传:

package com.sheye.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
 * 同一个协议下端口不允许冲突
 * 文件的上传:发送端:
 * 1.使用DatagramSocket 指定端口 创建发送端
 * 2.将基本数据类型 转成字节数组
 * 3.封装成DatagramPacket包裹	需要指定目的地
 * 4.发送包裹send(DatagramPacket p)
 * 5.释放资源
 * 
 * @author Administrator
 *从8888端口发送到9999端口
 */
public class UdpFileClient {

	public static void main(String[] args) throws Exception {
		System.out.println("客户端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		//2.准备数据 将基本数据类型 转成字节数组
		byte[] datas = IOUtils.fileToByteArray("src/1.jpg");
		
		
		//3.封装成DatagramPacket包裹	需要指定目的地
		DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
				new InetSocketAddress("localhost",9999));
		//4.发送包裹send(DatagramPacket p)
		client.send(packet);
		//5.释放资源
		client.close();
	}
}

文件存储:

package com.sheye.udp;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * 文件的存储:接收端(服务器进行接受)
 * 1.使用DatagramSocket 指定端口 创建接受端
 * 2.准备容器 封装成DatagramPacket包裹
 * 3.阻塞式接收包裹receive(DatagramPacket p)
 * 4.分析数据	将字节数组转化为对应的基本数据类型
 * 		byte[] getData()
 * 		int getLength()
 * 5.释放资源
 * @author Administrator
 *
 */
public class UpdFileServer {

	public static void main(String[] args) throws Exception {
		System.out.println("服务端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建接受端
		DatagramSocket server = new DatagramSocket(9999);
		//2.准备容器 封装成DatagramPacket包裹
		byte[] container = new byte[1024*60];
		DatagramPacket packet = new DatagramPacket(container,0,container.length);
		//3.阻塞式接收包裹receive(DatagramPacket p)
		server.receive(packet);	//阻塞式接
		//4.分析数据 将字节数组转化为对应的基本数据类型
		byte[] datas = packet.getData();
		int len = packet.getLength();
		IOUtils.byteArrayToFile(datas, "src/2.jpg");
	
		//5.释放资源
		server.close();
	}
}

UDP案列----在线咨询:
1.一方发送一方接受:
发送端:

package com.sheye.udp;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
 * 同一个协议下端口不允许冲突
 * 发送端--多次交流:
 * 1.使用DatagramSocket 指定端口 创建发送端
 * 2.准备数据 一定转成字节数组
 * 3.封装成DatagramPacket包裹	需要指定目的地
 * 4.发送包裹send(DatagramPacket p)
 * 5.释放资源
 * @author Administrator
 *从8888端口发送到9999端口
 */
public class UdpTalkClient {

	public static void main(String[] args) throws Exception {
		System.out.println("客户端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建发送端
		DatagramSocket client = new DatagramSocket(8888);
		//2.准备数据 一定转成字节数组
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		while (true) {
			String msg = br.readLine();
			byte[] datas = msg.getBytes();
			//3.封装成DatagramPacket包裹	需要指定目的地
			DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
					new InetSocketAddress("localhost",9999));
			//4.发送包裹send(DatagramPacket p)
			client.send(packet);
			if (msg.equals("bye")) {
				break;
			}
		}
		
		//5.释放资源
		client.close();
	}
}

接受端:

package com.sheye.udp;

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

/**
 * 接收端--多次交流(服务器进行接受):
 * 1.使用DatagramSocket 指定端口 创建接受端
 * 2.准备容器 封装成DatagramPacket包裹
 * 3.阻塞式接收包裹receive(DatagramPacket p)
 * 4.分析数据
 * 		byte[] getData()
 * 		int getLength()
 * 5.释放资源
 * @author Administrator
 *
 */
public class UpdTalkServer {

	public static void main(String[] args) throws Exception {
		System.out.println("服务端启动中。。。。。");
		//1.使用DatagramSocket 指定端口 创建接受端
		DatagramSocket server = new DatagramSocket(9999);
		//2.准备容器 封装成DatagramPacket包裹
		while (true) {
			byte[] container = new byte[1024*60];
			DatagramPacket packet = new DatagramPacket(container,0,container.length);
			//3.阻塞式接收包裹receive(DatagramPacket p)
			server.receive(packet);	//阻塞式接
			//4.分析数据
			byte[] datas = packet.getData();
			String data = new String(datas,0,datas.length);
			System.out.println(data);
			if (data.equals("bye")) {
				break;
			}
		}
		//5.释放资源
		server.close();
	}
}

2.多线程可实现一方同时接收和发送:
TalkSender:

package com.sheye.udp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

/**
 * 发送端:使用面向对象封装
 * @author Administrator
 *
 */
public class TalkSender implements Runnable{
	
	private DatagramSocket client;
	private BufferedReader br;
	private String destIP;
	private int destPort;
	
	public TalkSender(int srcPort,String destIP,int destPort) {
		this.destIP = destIP;
		this.destPort = destPort;
		try {
			client = new DatagramSocket(srcPort);
			br = new BufferedReader(new InputStreamReader(System.in));
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}
	
	public void run() {
		while (true) {
			String msg;
			try {
				msg = br.readLine();
				byte[] datas = msg.getBytes();
				//3.封装成DatagramPacket包裹	需要指定目的地
				DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
						new InetSocketAddress(destIP,destPort));
				//4.发送包裹send(DatagramPacket p)
				client.send(packet);
				if (msg.equals("bye")) {
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//5.释放资源
		client.close();
	}
}

TalkReceive:

package com.sheye.udp;

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

/**
 * 接受端
 * @author Administrator
 *
 */
public class TalkReceive implements Runnable{
	
	private DatagramSocket server;
	
	public TalkReceive(int srcPort) {
		try {
			server = new DatagramSocket(srcPort);
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}
	public void run() {
		while (true) {
			byte[] container = new byte[1024*60];
			DatagramPacket packet = new DatagramPacket(container,0,container.length);
			//3.阻塞式接收包裹receive(DatagramPacket p)
			try {
				server.receive(packet);
				//4.分析数据
				byte[] datas = packet.getData();
				String data = new String(datas,0,datas.length);
				System.out.println(data);
				if (data.equals("bye")) {
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//5.释放资源
		server.close();	
	}
}

TalkStudent:

package com.sheye.udp;

/**
 * 加入多线程实现双向交流 模拟在线咨询
 * @author Administrator
 *
 */
public class TalkStudent {

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

TalkTeacher:

package com.sheye.udp;

public class TalkTeacher {

	public static void main(String[] args) {
		//接收
		new Thread(new TalkReceive(9999)).start();
		//发送
		new Thread(new TalkSender(5555, "localhost", 6666)).start();
	}
}

UDP组播:
发送方:

package com.sheye.udp;
import java.net.*;
import java.io.*;

public class MulticastSender {
  public static void main(String[] args) throws Exception{
   
    InetAddress group = InetAddress.getByName("226.0.0.1");
    MulticastSocket ms =  new MulticastSocket();
  
    ms.joinGroup(group);
   
    String msg = "Hello,everybody! " ; 
    byte[] b = msg.getBytes(); 
    DatagramPacket dp = new DatagramPacket(b, b.length,group,5678);
    ms.send(dp);  
    System.out.println("发送问候给"+group+":"+ 5678);
       
    ms.close();           
       
  }
}

接收方:

package com.sheye.udp;
import java.net.*;

import java.io.*;

public class MulticastReceiver {
  
    public static void main(String[] args) throws IOException{
    
        InetAddress group=InetAddress.getByName("226.0.0.1");
        
        MulticastSocket ms = new MulticastSocket(5678);
        ms.joinGroup(group);
      
        byte[] b = new byte[100];
       
        DatagramPacket dp = new DatagramPacket(b, b.length);
        ms.receive(dp);  
            
        String str = new String(dp.getData(),0,dp.getLength());
        System.out.print("从 " + dp.getAddress().toString()+":" + dp.getPort()+"收到消息");
        System.out.println(str);
               
        ms.leaveGroup(group);
        ms.close();
        
    }
        
}

TCP:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
建立连接之后,流在socket中传输

一.TCP基本步骤:

想象一下一个浏览器向一个服务器进行请求,浏览器是不是要知道服务器的ip和端口,而服务器只需要暴露一个端口号即可,所以浏览器的socket要有ip和port,而serversocket只需要有port

服务端:

package com.sheye.tcp;

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

/**
 * 熟悉流程
 * 创建服务器
 * 1.指定端口 使用serversocket创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 * @author Administrator
 *
 */
public class Server {

	public static void main(String[] args) throws IOException {
		System.out.println("--------------Server--------------------");
		//指定端口 使用serversocket创建服务器
		ServerSocket server = new ServerSocket(8888);
		//2.阻塞式等待连接 accept
		Socket client = server.accept();
		//3.操作:输入输出流操作
		DataInputStream dis = new DataInputStream(client.getInputStream());
		String data = dis.readUTF();
		System.out.println(data);
		//4.释放资源
		dis.close();
		client.close();
	}
}

客户端:

package com.sheye.tcp;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 熟悉流程
 * 创建客户端
 * 1.使用socket创建客户端 + 指定服务器的地址和端口
 * 2.操作:输入输出流操作
 * 3.释放资源
 * @author Administrator
 *
 */
public class Client {

	public static void main(String[] args) throws UnknownHostException, 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();
	}
}

二.TCP案例----文件上传:
1.模拟登陆 单向:
服务端:

package com.sheye.tcp;


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

/**
 * 模拟登陆 单向
 * 创建服务器
 * 1.指定端口 使用serversocket创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 * @author Administrator
 *
 */
public class LoginServer {

	public static void main(String[] args) throws IOException {
		System.out.println("--------------Server--------------------");
		
		//指定端口 使用serversocket创建服务器
		ServerSocket server = new ServerSocket(8888);
		//2.阻塞式等待连接 accept
		Socket client = server.accept();
		//3.操作:输入输出流操作
		DataInputStream dis = new DataInputStream(client.getInputStream());
		//分析
		String data = dis.readUTF();
		String[] dataArray  = data.split("&");
		for (String info : dataArray) {
			String[] userInfo = info.split("=");
			//System.out.println(userInfo[0]+":"+userInfo[1]);
			if (userInfo[0].equals("uname")) {
				System.out.println("您的用户名为:"+userInfo[1]);
			}else if (userInfo[0].equals("pwd")) {
				System.out.println("您的密码为:"+userInfo[1]);
			}
		}
		//4.释放资源
		dis.close();
		client.close();
	}
}

客户端:

package com.sheye.tcp;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 熟悉流程
 * 创建客户端
 * 1.使用socket创建客户端 + 指定服务器的地址和端口
 * 2.操作:输入输出流操作
 * 3.释放资源
 * @author Administrator
 *
 */
public class LoginClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入账户");
		String uname = br.readLine();
		System.out.println("请输入密码");
		String pwd = br.readLine();
		
		 //1.使用socket创建客户端 + 指定服务器的地址和端口
		 Socket client = new Socket("localhost",8888);
		 //2.操作:输入输出流操作
		 DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		 
		 dos.writeUTF("uname="+uname+"&"+"pwd="+pwd);
		 dos.flush();
		 //3.释放资源
		 dos.close();
		 client.close();
	}
}

2.模拟登陆 双向:
服务端:

package com.sheye.tcp;


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

/**
 * 模拟登陆 双向
 * 创建服务器
 * 1.指定端口 使用serversocket创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 * @author Administrator
 *
 */
public class LoginTwoWayServer {

	public static void main(String[] args) throws IOException {
		System.out.println("--------------Server--------------------");
		
		//指定端口 使用serversocket创建服务器
		ServerSocket server = new ServerSocket(8888);
		//2.阻塞式等待连接 accept
		Socket client = server.accept();
		//3.操作:输入输出流操作
		DataInputStream dis = new DataInputStream(client.getInputStream());
		String uname = "";
		String pwd = "";
		//分析
		String data = dis.readUTF();
		String[] dataArray  = data.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("pwd")) {
				System.out.println("您的密码为:"+userInfo[1]);
				pwd=userInfo[1];
			}
		}
		
		//输出
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		
		
		if (uname.equals("sheye") && pwd.equals("qq3200334")) {
			dos.writeUTF("登陆成功");
		}else {
			dos.writeUTF("用户名密码错误");
		}
		
		//4.释放资源
		dis.close();
		client.close();
	}
}

客户端:

package com.sheye.tcp;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 模拟登陆 双向
 * 熟悉流程
 * 创建客户端
 * 1.使用socket创建客户端 + 指定服务器的地址和端口
 * 2.操作:输入输出流操作
 * 3.释放资源
 * @author Administrator
 *
 */
public class LoginTwoWayClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入账户");
		String uname = br.readLine();
		System.out.println("请输入密码");
		String pwd = br.readLine();
		
		 //1.使用socket创建客户端 + 指定服务器的地址和端口
		 Socket client = new Socket("localhost",8888);
		 //2.操作:输入输出流操作
		 DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		 
		 dos.writeUTF("uname="+uname+"&"+"pwd="+pwd);
		 dos.flush();
		 
		 DataInputStream dis = new DataInputStream(client.getInputStream());
		 String result = dis.readUTF();
		 System.out.println(result);
		 //3.释放资源
		 dos.close();
		 client.close();
	}
}

3.文件上传
服务端:

package com.sheye.tcp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 熟悉流程
 * 创建服务器
 * 1.指定端口 使用serversocket创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 * @author Administrator
 *
 */
public class FileServer {

	public static void main(String[] args) throws IOException {
		System.out.println("--------------Server--------------------");
		//指定端口 使用serversocket创建服务器
		ServerSocket server = new ServerSocket(8888);
		//2.阻塞式等待连接 accept
		Socket client = server.accept();
		//3.操作:文件的拷贝
		InputStream is = new BufferedInputStream(client.getInputStream());
		OutputStream os = new BufferedOutputStream(new FileOutputStream("src/2.jpg"));
		 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();
	}
}

客户端:

package com.sheye.tcp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 熟悉流程
 * 创建客户端
 * 1.使用socket创建客户端 + 指定服务器的地址和端口
 * 2.操作:输入输出流操作
 * 3.释放资源
 * @author Administrator
 *
 */
public class FileClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");
		 //1.使用socket创建客户端 + 指定服务器的地址和端口
		 Socket client = new Socket("localhost",8888);
		 //2.操作:拷贝
		 InputStream is = new BufferedInputStream(new FileInputStream("src/1.jpg"));
		 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();
	}
}

三.TCP案例----多用户登陆:
服务端:

package com.sheye.tcp;

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

/**
 * 模拟登陆 双向 创建服务器 1.指定端口 使用serversocket创建服务器 2.阻塞式等待连接 accept 3.操作:输入输出流操作 4.释放资源
 * 
 * @author Administrator
 *
 */
public class LoginMultiServer {

	public static void main(String[] args) throws IOException {
		System.out.println("--------------Server--------------------");

		// 指定端口 使用serversocket创建服务器
		ServerSocket server = new ServerSocket(8888);
		// 2.阻塞式等待连接 accept
		boolean isRunning = true;
		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();
			}
		}

		public void run() {
			String uname = "";
			String pwd = "";

			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("pwd")) {
					System.out.println("您的密码为:" + userInfo[1]);
					pwd = userInfo[1];
				}
			}

			if (uname.equals("sheye") && pwd.equals("qq3200334")) {
				send("登陆成功");
			} else {
				send("登陆失败");
			}
			
			release();
		}

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

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

		}

		// 释放资源
		public void release() {
			try {
				dos.flush();
				dis.close();
				client.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			
		}

	}
}

客户端:

package com.sheye.tcp;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 模拟登陆 多个客户端请求 熟悉流程 创建客户端 1.使用socket创建客户端 + 指定服务器的地址和端口 2.操作:输入输出流操作 3.释放资源
 * 
 * @author Administrator
 *
 */
public class LoginMultiClient {
	
	//此处先发送再响应,如果同时发送同时响应可以使用多线程
	public static void main(String[] args) throws UnknownHostException, 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 br;
		private String msg;
		
		public Send(Socket client) {		 
			br= new BufferedReader(new InputStreamReader(System.in));
			msg = init();
			this.client = client;
			try {
				// 2.操作:输入输出流操作
				dos = new DataOutputStream(client.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		private String init() {
			try {
				System.out.println("请输入账户");
				String uname = br.readLine();
				System.out.println("请输入密码");
				String pwd = br.readLine();
				return "uname="+uname+"&"+"pwd"+pwd;
			} catch (IOException e) {
				e.printStackTrace();
			}
			return "";
		}
		
		public void send() {
			try {
				dos.writeUTF(msg);
				dos.flush();
				// 3.释放资源 刚开始在这里关闭流提示了空指针异常 原因是如果在此处关闭流 
				//相当于outputstream 和 inputstream 中间 加入os.close() 那么inputstream接收不到了
				//dos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}	
		}
	}

	//接收
	static class Receive {
		private DataInputStream dis;
		private Socket client;
			
		
		public Receive(Socket client) {
			this.client = client;
			try {
				dis = new DataInputStream(client.getInputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}

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

}

在线聊天室:
一.实现一对一聊天(客户端自言自语,发送给服务端,服务端转发回来)
在这里插入图片描述
1.在线聊天室 客户端 目标 实现一个客户能够正常地收发信息:
服务端:

package com.sheye.chat01;

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

/**
 * 在线聊天室 服务端 目标 实现一个客户能够正常地收发信息
 * 
 * @author Sheye
 *
 */
public class Chat {

	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 msg = dis.readUTF();
		System.out.println(msg);

		// 4.返回消息
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		dos.writeUTF(msg);
		dos.flush();

		//5.释放资源
		dos.close();
		dis.close();
		client.close();
	}
}

客户端:

package com.sheye.chat01;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 目标 实现一个客户能够正常地收发信息
 * 
 * @author Sheye
 *
 */
public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");

		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);
		
		//2.客户端发送消息
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String msg = br.readLine();
		
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		dos.writeUTF(msg);
		dos.flush();

		//3.客户端接收消息
		DataInputStream dis = new DataInputStream(client.getInputStream());
		msg = dis.readUTF();
		System.out.println(msg);
		
		//4.释放资源
		dos.close();
		dis.close();
		client.close();
	}
}
  1. 在线聊天室 客户端 目标 实现一个客户能够正常连续地收发信息:
    服务端:
package com.sheye.chat01;

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

/**
 * 在线聊天室 服务端 目标 实现一个客户能够正常连续地收发信息
 * 
 * @author Sheye
 *
 */
public class MutiChat {

	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());
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		
		boolean isRunning = true;
		while (isRunning) {
			String msg = dis.readUTF();
			System.out.println(msg);
			// 4.返回消息
			dos.writeUTF(msg);
			dos.flush();
		}

		//5.释放资源
		dos.close();
		dis.close();
		client.close();
	}
}

客户端:

package com.sheye.chat01;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 目标 实现一个客户能够正常连续地收发信息
 * 
 * @author Sheye
 *
 */
public class MutiClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");

		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);

		// 2.客户端发送消息
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		DataInputStream dis = new DataInputStream(client.getInputStream());

		boolean isRunning = true;
		while (isRunning) {
			String msg = br.readLine();
			dos.writeUTF(msg);
			dos.flush();
			// 3.客户端接收消息
			msg = dis.readUTF();
			System.out.println(msg);
		}

		// 4.释放资源
		dos.close();
		dis.close();
		client.close();
	}
}

3.直接在accept处加入死循环导致每个客户端进入之后排队地错误:
服务端:

package com.sheye.chat02;

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

/**
 * 在线聊天室 服务端 目标 实现多个客户能够正常地收发信息
 * 问题 其他客户必须等待之前地客户退出 才能继续 排队
 * @author Sheye
 *
 */
public class MutiChat {

	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("一个客户端建立了连接");

			// 3.接收消息
			DataInputStream dis = new DataInputStream(client.getInputStream());
			DataOutputStream dos = new DataOutputStream(client.getOutputStream());
			
			boolean isRunning = true;
			while (isRunning) {
				String msg = dis.readUTF();
				System.out.println(msg);
				// 4.返回消息
				dos.writeUTF(msg);
				dos.flush();
			}

			//5.释放资源
			dos.close();
			dis.close();
			client.close();
		}	
	}
}

客户端:

package com.sheye.chat02;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 目标 实现多个客户能够正常地收发信息
 * 
 * @author Sheye
 * 问题 其他客户必须等待之前地客户退出 才能继续 排队
 */
public class MutiClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");

		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);

		// 2.客户端发送消息
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		DataInputStream dis = new DataInputStream(client.getInputStream());

		boolean isRunning = true;
		while (isRunning) {
			String msg = br.readLine();
			dos.writeUTF(msg);
			dos.flush();
			// 3.客户端接收消息
			msg = dis.readUTF();
			System.out.println(msg);
		}

		// 4.释放资源
		dos.close();
		dis.close();
		client.close();
	}
}

在这里插入图片描述
只有右下角地client才能进行收发,而右上角的client无法进行收发

4.为解决3的问题,加入多线程:
在这里插入图片描述
非多线程,只能串行运行,也就是排队机制
在这里插入图片描述
多线程并行机制,每一个client连接上serversocket 创建一个新的线程 并行运行
服务端:

package com.sheye.chat02;

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

/**
 * 在线聊天室 服务端
 *  目标 使用多线程实现多个客户能够正常地收发信息
 * 问题
 * 1 代码不好维护
 * 2 客户端读写没有分开 必须先发送一条信息 才能接收一条信息
 * @author Sheye
 *
 */
public class ThreadMutiChat {

	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(()->{
				DataInputStream dis = null;
				DataOutputStream dos = null;
				boolean isRunning = true;
				try {
					dis = new DataInputStream(client.getInputStream());
					dos = new DataOutputStream(client.getOutputStream());
					
					while (isRunning) {
						String msg = dis.readUTF();
						System.out.println(msg);
						// 4.返回消息
						dos.writeUTF(msg);
						dos.flush();
					}

				} catch (IOException e) {
					isRunning=false;//出错停止线程
				}
				
				
				
				//5.释放资源
				try {
					if (dos!=null && dis!=null && client!=null) {
						dis.close();
						dos.close();
						client.close();
					}	
				} catch (IOException e) {
					
					e.printStackTrace();
				}
				
			}).start();	
		}	
	}
}

客户端:

package com.sheye.chat02;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 
 * 目标 使用多线程 实现多个客户能够正常地收发信息
 * 
 * @author Sheye
 *
 */
public class ThreadMutiClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");

		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);

		// 2.客户端发送消息
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
		DataInputStream dis = new DataInputStream(client.getInputStream());

		boolean isRunning = true;
		while (isRunning) {
			String msg = br.readLine();
			dos.writeUTF(msg);
			dos.flush();
			// 3.客户端接收消息
			msg = dis.readUTF();
			System.out.println(msg);
		}

		// 4.释放资源
		dos.close();
		dis.close();
		client.close();
	}
}

在这里插入图片描述
多线程实现多个client可以进行收发 但是 客户端读写没有分开 必须先发送一条信息 才能接收一条信息客户端读写没有分开 必须先发送一条信息 才能接收一条信息,代码不好维护

5.为解决4的问题,将客户端的发送和接收分别封装加入多线程
释放资源方法来自3的SyUtils类中

4的问题:
1 代码不好维护
2 客户端读写没有分开 必须先发送一条信息 才能接收一条信息

客户端的发送:

package com.sheye.chat03;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 使用多线程封装了发送端
 * 1.发送信息
 * 2.从控制台获取资源
 * 3.释放资源
 * 4.重写run
 * 
 * @author Sheye 此处为解决接和收的分离 创建的两个类
 */
public class Send implements Runnable {

	private BufferedReader br;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;

	public Send(Socket client) {
		isRunning = true;
		this.client = client;
		try {
			br = new BufferedReader(new InputStreamReader(System.in));
			dos = new DataOutputStream(client.getOutputStream());
		} catch (Exception e) {
			release();
			System.out.println("发送端构造失败");
		}
	}

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

	// 从控制台获取消息
	private String getStrFromBr() {
		try {
			return br.readLine();
		} catch (IOException e) {
			release();
			System.out.println("getStrFromBr()出错");
		}
		return "";
	}

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

	}

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

}

客户端的接收:

package com.sheye.chat03;

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

/**
 * 使用多线程封装了接收端
 * 1.接收信息
 * 2.释放资源
 * 3.重新了run
 * @author Sheye
 *此处为解决接和收的分离 创建的两个类
 *
 */
public class Receive implements Runnable{

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

	public void run() {
		while (isRunning) {
			String msg = receive();
			if (!msg.equals("")) {
				System.out.println(msg);
			}
			
		}	
	}
	
	private String receive() {
		String msg="";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			release();
			System.out.println("receive()出错");
		}
		return msg;
	}
	
	// 释放资源
		private void release() {
			isRunning = false;
			SyUtils.close(dis, client);
		}
}

客户端的主方法:

package com.sheye.chat03;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 
 * 目标 使用多线程 实现多个客户能够正常地收发信息
 * 
 * @author Sheye
 *
 */
public class ThreadMutiClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");

		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);

		// 2.客户端发送消息
		new Thread(new Send(client)).start();
		new Thread(new Receive(client)).start();
		
	}
}

服务端:

package com.sheye.chat03;

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

/**
 * 在线聊天室 服务端 目标 封装使用多线程实现多个客户能够正常地收发信息 问题 1 代码不好维护 2 客户端读写没有分开 必须先发送一条信息
 * 才能接收一条信息
 * 
 * @author Sheye
 *
 */
public class ThreadMutiChat {

	public static void main(String[] args) throws IOException {
		System.out.println("--------------Server--------------------");

		// 1.指定端口 使用serversocket创建服务器
		ServerSocket server = new ServerSocket(8888);
		while (true) {
			Socket client = server.accept();
			System.out.println("一个客户端建立了连接");
			new Thread(new Channel(client)).start();
			
		}

	}

	/**
	 * 
	 * @author Sheye 静态方法中只能调用静态方法和静态变量 非静态方法 可以调用静态方法和静态变量
	 * https://blog.csdn.net/qq_35499112/article/details/84886871
	 */
	// 一个客户代表一个线程
	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();// 出错 直接就可以释放资源
			}
		}

		@Override
		public void run() {
			while (isRunning) {
				String msg = receive();
				if (null != msg) {
					send(msg);
				}
			}

		}

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

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

		}

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

	}
}

二.实现群聊
释放资源方法来自3的SyUtils类中
客户端发送:

package com.sheye.chat04;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 使用多线程封装了发送端
 * 1.发送信息
 * 2.从控制台获取资源
 * 3.释放资源
 * 4.重写run
 * 
 * @author Sheye 此处为解决接和收的分离 创建的两个类
 */
public class Send implements Runnable {

	private BufferedReader br;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;
	private String name;

	public Send(Socket client,String name) {
		isRunning = true;
		this.client = client;
		this.name=name;
		try {
			br = new BufferedReader(new InputStreamReader(System.in));
			dos = new DataOutputStream(client.getOutputStream());
			//发送名称	刚建立管道 就发送名称 初始化就发送
			send(name);
		} catch (Exception e) {
			release();
			System.out.println("发送端构造失败");
		}
	}

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

	// 从控制台获取消息
	private String getStrFromBr() {
		try {
			return br.readLine();
		} catch (IOException e) {
			release();
			System.out.println("getStrFromBr()出错");
		}
		return "";
	}

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

	}

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

}

客户端接收:

package com.sheye.chat04;

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

/**
 * 使用多线程封装了接收端
 * 1.接收信息
 * 2.释放资源
 * 3.重新了run
 * @author Sheye
 *此处为解决接和收的分离 创建的两个类
 *
 */
public class Receive implements Runnable{

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

	public void run() {
		while (isRunning) {
			String msg = receive();
			if (!msg.equals("")) {
				System.out.println(msg);
			}
			
		}	
	}
	
	private String receive() {
		String msg="";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			release();
			System.out.println("receive()出错");
		}
		return msg;
	}
	
	// 释放资源
		private void release() {
			isRunning = false;
			SyUtils.close(dis, client);
		}

}

客户端主方法:

package com.sheye.chat04;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 
 * 目标 使用多线程 实现多个客户能够正常地收发信息
 * 
 * @author Sheye
 *
 */
public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入用户名");
		String name = br.readLine();
		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);

		// 2.客户端发送消息
		new Thread(new Send(client,name)).start();
		new Thread(new Receive(client)).start();
		
	}
}

服务端:

package com.sheye.chat04;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 在线聊天室 服务端 目标 加入容器 实现群聊
 * 
 * @author Sheye
 *
 */
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);
		while (true) {
			Socket client = server.accept();
			System.out.println("一个客户端建立了连接");
			Channel c = new Channel(client);
			all.add(c); // 容器管理所有成员
			new Thread(c).start();

		}
	}

	/**
	 * 
	 * @author Sheye 静态方法中只能调用静态方法和静态变量 非静态方法 可以调用静态方法和静态变量
	 *         static->https://blog.csdn.net/qq_35499112/article/details/84886871
	 */
	// 一个客户代表一个线程
	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();
				//欢迎你到来
				send("欢迎你的到来");
				
				sendOthers(name+"来到了聊天室",true);
			} catch (IOException e) {
				release();// 出错 直接就可以释放资源
			}
		}

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

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

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

		// 群聊 获取自己的消息 发送给其他人	isSys是否为系统消息
		private void sendOthers(String msg,boolean isSys) {
			for (Channel other : all) {
				if (other == this) { // 自己不能跟自己对话
					continue;
				}
				if (!isSys) {	//不是系统消息
					other.send(name+"对所有人说:"+msg);	//群聊消息
				}else {
					other.send(msg);	//系统消息	
				}
				
			}
		}

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

	}
}

三.私聊
释放资源方法来自3的SyUtils类中

客户端接收:

package com.sheye.chat05;

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

/**
 * 使用多线程封装了接收端
 * 1.接收信息
 * 2.释放资源
 * 3.重新了run
 * @author Sheye
 *此处为解决接和收的分离 创建的两个类
 *
 */
public class Receive implements Runnable{

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

	public void run() {
		while (isRunning) {
			String msg = receive();
			if (!msg.equals("")) {
				System.out.println(msg);
			}
			
		}	
	}
	
	private String receive() {
		String msg="";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			release();
			System.out.println("receive()出错");
		}
		return msg;
	}
	
	// 释放资源
		private void release() {
			isRunning = false;
			SyUtils.close(dis, client);
		}

}

客户端发送:

package com.sheye.chat05;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 使用多线程封装了发送端
 * 1.发送信息
 * 2.从控制台获取资源
 * 3.释放资源
 * 4.重写run
 * 
 * @author Sheye 此处为解决接和收的分离 创建的两个类
 */
public class Send implements Runnable {

	private BufferedReader br;
	private DataOutputStream dos;
	private Socket client;
	private boolean isRunning;
	private String name;

	public Send(Socket client,String name) {
		isRunning = true;
		this.client = client;
		this.name=name;
		try {
			br = new BufferedReader(new InputStreamReader(System.in));
			dos = new DataOutputStream(client.getOutputStream());
			//发送名称	刚建立管道 就发送名称 初始化就发送
			send(name);
		} catch (Exception e) {
			release();
			System.out.println("发送端构造失败");
		}
	}

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

	// 从控制台获取消息
	private String getStrFromBr() {
		try {
			return br.readLine();
		} catch (IOException e) {
			release();
			System.out.println("getStrFromBr()出错");
		}
		return "";
	}

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

	}

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

客户端主方法:

package com.sheye.chat05;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 在线聊天室 客户端 
 * 目标 使用多线程 实现多个客户能够正常地收发信息
 * 
 * @author Sheye
 *
 */
public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("--------------Client--------------------");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入用户名");
		String name = br.readLine();
		// 1.使用socket创建客户端 + 指定服务器的地址和端口
		Socket client = new Socket("localhost", 8888);

		// 2.客户端发送消息
		new Thread(new Send(client,name)).start();
		new Thread(new Receive(client)).start();
		
	}
}

服务端:

package com.sheye.chat05;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 在线聊天室 服务端 
 * 目标 私聊
 * @author Sheye
 *
 */
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);
		while (true) {
			Socket client = server.accept();
			System.out.println("一个客户端建立了连接");
			Channel c = new Channel(client);
			all.add(c); // 容器管理所有成员
			new Thread(c).start();

		}
	}

	/**
	 * 
	 * @author Sheye 静态方法中只能调用静态方法和静态变量 非静态方法 可以调用静态方法和静态变量
	 *         static->https://blog.csdn.net/qq_35499112/article/details/84886871
	 */
	// 一个客户代表一个线程
	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();
				// 欢迎你到来
				send("欢迎你的到来");

				sendOthers(name + "来到了聊天室", true);
			} catch (IOException e) {
				release();// 出错 直接就可以释放资源
			}
		}

		@Override
		public void run() {
			while (isRunning) {
				String msg = receive();
				if (null != msg) {
					sendOthers(msg, false);
				}
			}
		}

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

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

		/**
		 * 群聊 获取自己的消息 发送给其他人
		 *  私聊 约定数据格式 @xxx:msg
		 * @param msg
		 * @param isSys 是否为系统消息
		 */
		private void sendOthers(String msg, boolean isSys) {
			boolean isPrivate = msg.startsWith("@");
			if (isPrivate) { // 私聊
				int idx = msg.indexOf(":");
				String targetName = msg.substring(1, idx); // substring左闭右开
				msg = msg.substring(idx + 1);
				for (Channel other : all) {
					if (other.name.equals(targetName)) {
						other.send(name + "对您说:" + msg);
					}
				}
			} else {
				for (Channel other : all) {
					if (other == this) { // 自己不能跟自己对话
						continue;
					}
					if (!isSys) { // 不是系统消息
						other.send(name + "对所有人说:" + msg);
					} else {
						other.send(msg);
					}
				}
			}

		}

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

	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值