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();
}
}
- 在线聊天室 客户端 目标 实现一个客户能够正常连续地收发信息:
服务端:
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);
}
}
}