一基本概念
IP
用来标识网络中的一个通信实体的地址。
通信实体可以是 计算机,路由器等。
路由器:连接两个或多个网络的网络设备。
IPV4: 32位地址, 以点分十进制表示,192.168.0.1
IPV6:128位(16字节) 写成8个16位的无符号整数,每个整数用4个16进制位表示,数之间用(冒号:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
特殊的IP:
127.0.0.1 本机地址
192.168.0.0 – 192.16.255.255 私有地址,属于非注册地址,专门为组织机构内部使用。
/**
* IP : 定位一个节点:计算机 路由器 通讯设备等等
* InetAddress : 封装计算机的ip 地址,没有端口。
* 1.getLocalHost : 本机
* 2.getByName : 根据域名DNS或Ip地址 ---解析--》IP
*
* .两个成员方法:
* 1.getHostAddress : 返回地址
* 2.getHostName: 返回计算机名
* @author admin
*
*/
public class IPTest {
public static void main(String[] args) throws UnknownHostException {
//使用getLocalHost方法创建InetAddress对象 本机
InetAddress addr = InetAddress.getLocalHost();
System.out.println(addr.getHostAddress()); //返回: 本机地址
System.out.println(addr.getHostName()); //返回: 本机计算机名字
//根据域名得到InetAddress 对象
addr = InetAddress.getByName("www.shsxt.com");
System.out.println(addr.getHostAddress()); //返回: shsxt服务器的ip
System.out.println(addr.getHostName()); //输出: www.shxst.com
//根据Ip得到InetAddress 对象
addr = InetAddress.getByName("123.56.138.176");
System.out.println(addr.getHostAddress()); //返回shsxt的ip : 123.56.138.176
System.out.println(addr.getHostName()); //输出ip 而不是域名。如果这个ip 地址不存在或者DNS服务器不允许进行IP地址和域名的映射
//getHostName放法直接返会这个Ip地址。
}
}
端口
IP用来表示一台计算机。
端口表示是一个16位的二进制整数,2个字节,对应十进制的0—65535
端口是虚拟的概念。用来区分软件的
通过端口,可以在一个主机上运行多个网络应用程序。
公认端口 0–1023
注册端口 1024 --49151
动态/私有端口 49152 – 65535
查看所有端口: netstat -ano
查看指定端口: netstat -ano | findstr “808”
查看指定进程: tasklist | findstr “808”
查看具体程序:使用任务管理器查看PID
/**
* 端口
* 1.区分软件
* 2.2个字节 0 --65535 UDP TCP协议不一样
* 3.同一个协议端口不能冲突
* 4.定义端口越大越好
* @author admin
*1.构造器
*new InetSocketAddress(地址|域名|, 端口);
*2.方法
*getAddress() : 地址
*getPort() : 端口
*InetSocketAddress
*/
public class PortTest {
public static void main(String[] args) {
//包含端口
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);
InetSocketAddress socketAddress2 = new InetSocketAddress("localhost",9000);
System.out.println(socketAddress.getHostName());
System.out.println(socketAddress.getAddress());
System.out.println(socketAddress2.getAddress());
System.out.println(socketAddress2.getPort());
}
}
URL :统一资源定位器
/**
* URL : 统一资源定位器 互联网三大基石之一(html http) 区分资源
* 组成部分
* 1.协议
* 2.域名 、计算机
* 3.端口 :默认80
* 4.资源文件名
* @author admin
*
*/
public class URLTest01 {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://www.baidu.com:80/index.html?uname=shsxt&age=18#a");
//获取四个值
System.out.println("协议: " + url.getProtocol());
System.out.println("域名IP: " + url.getHost());
System.out.println("端口: " + url.getPort());
System.out.println("请求资源1: " + url.getFile());
System.out.println("请求资源2: " + url.getPath());
//参数
System.out.println("参数:" + url.getQuery());
//锚点
System.out.println("锚点:" + url.getRef());
}
}
简单网络爬虫
public class SpiderTest{
public static void main(String[] args){
//获取URL
URL url = new URL("http://www.jd.com");
//下载资源
InputStream is = url.openStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
String str = null;
while(null != (str=br.readline())){
System.out.println(str);
}
br.close();
//分析
//处理
}
}
UDP编程
DataGramSocket : 用于发送或接收数据包的套接字
DatagramPacket : 数据包
/**
*发送端
*1.使用 DatagramSocket 指定端口 创建发送端
*2.准备数据 一定要转成字节数组
*3.封装成DatagramPacket 包裹,需要指定目的地
*4.发送包裹 send(DatagramPacket p)
* 5.释放资源
* @author admin
*
*/
public class UdpClient {
public static void main(String[] args) throws IOException {
System.out.println("发送端启动中。。。。");
//1.使用 DatagramSocket 指定端口 创建发送端
DatagramSocket client = new DatagramSocket(6666);
//2.准备数据 一定要转成字节数组
String str = "我爱你";
byte[] datas = str.getBytes();
//3.封装成DatagramPacket 包裹,需要指定目的地
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",8888));
//4.发送包裹 send(DatagramPacket p)
client.send(packet);
// 5.释放资源
client.close();
}
}
/**
*接收端
*1.使用 DatagramSocket 指定端口 创建接收端
*2.准备容器 封装成DataGramPacket 包裹
*3.阻塞式接收包裹 receive (DatagramPacket p)
*4.分析数据
* byte[] getData()
* getLength()
* 5.释放资源
*
* @author admin
*
*/
public class UdpServer {
public static void main(String[] args) throws IOException {
System.out.println("接收端启动中。。。。");
//1.使用 DatagramSocket 指定端口 创建接收端
DatagramSocket server = new DatagramSocket(8888);
//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[] msg = packet.getData();
int len = packet.getLength();
System.out.println(new String(msg,0,len));
//5.释放资源
server.close();
}
}
UDP–操作基本对象
//发送端
public class UdpTypeClient{
public static void main(String[] args){
//1.利用DatagramSocket 创建发送端 指定端口
DatagramSocket client = new DatagramSocket(8888);
//2.准备数据 一定转化为字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
//写出
dos.writeUTF("爱你");
dos.writeInt(3);
dos.writeBoolean(false);
dos.flush();
byte[] datas = baos.toByteArray();
//3.封装为DatagramPacket() 指定发送位置
DatagramPacket packet = new DatagramPacket(datas,0, datas.length, new InetSocketAddress("localhost",9999));
//4.发送
client.send(packet);
//5.关闭资源
client.close();
}
}
接收端
public class UdpTypeServer{
public static void main(String[] args){
//1.利用DatagramSocket 指定端口 创建接收端
DatagramSocket server = new DatagramSocket(9999);
//2.准备容器 并封装为DatagramPacket()
byte[] container = new byte[1024*64];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.阻塞式接收
server.receive(packet);
//4.数据处理 并转回到原来的类型
byty[] datas = packet.getByte();
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();
System.out.println(flag):
//5.释放资源
server.close();
}
}
UDP传文件
/**
* 文件发送: 发送端
* @author admin
*
*/
public class UdpFileClient {
public static void main(String[] args) throws IOException {
System.out.println("启动子。。。");
//1.利用DatagramSocket 指定端口 创建发送端
DatagramSocket client = new DatagramSocket(8888);
//2.准备数据 一定转化为字节数组
byte[] datas = UtileFile.fileToByteArray("C:\\Users\\admin\\Desktop\\D\\eclipse-workspace\\Net_study02\\src\\com\\sxt\\udp\\111.jpg");
//3.封装为 DatagramPacket
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",5789));
//4.发送
client.send(packet);
//5.释放资源
client.close();
}
}
/**
* 文件存储 :接收端
* @author admin
*
*/
public class UdpFileServer {
public static void main(String[] args) throws IOException {
System.out.println("启动子。。。");
//1.
DatagramSocket server = new DatagramSocket(5789);
//2.
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.
server.receive(packet);
//4.数据处理
byte[] datas = packet.getData();
int len = packet.getLength();
UtileFile.ByteArrayToFile(datas, "src/copy.jpg");
//5.释放资源
server.close();
}
}
//图片 – 》 文件
//1.图片–程序—字节数组
//2.字节数组 – 程序 – 文件
public class UtileFile {
//1. 图片 -- 》字节数组
public static byte[] fileToByteArray(String path) throws IOException {
//1.图片 --- 》 程序 FileInputStream
//2.程序------》字节数组 ByteArrayOutputstream
//1.创建源
File f = new File(path);
byte[] dest = null;
//2.选择流
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//3.操作
is = new FileInputStream(f);
baos = new ByteArrayOutputStream();
byte[] flush = new byte[1024*10];
int len = -1;
while((len = is.read(flush)) != -1) {
baos.write(flush,0,len); //写出到字节数组中
}
baos.flush();
return baos.toByteArray();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4.释放资源
if(null != is) {
is.close();
}
}
return null;
}
//2.字节数组 ---- 》文件
public static void ByteArrayToFile(byte[] bt, String path) throws IOException {
//1.字节数组 ---- 》 程序 ByteArrayInputStream
//2.程序 --- 》 文件 FileOutputStream
//1.创建源
//byte[] src =bt;
File f = new File(path);
//2.选择流
InputStream baos = null;
OutputStream os = null;
try {
//3.操作
baos = new ByteArrayInputStream(bt);
os = new FileOutputStream(f);
byte[] flush = new byte[5];
int len = -1;
while((len = baos.read(flush)) != -1){
os.write(flush,0,len); //写出到文件
}
os.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(null != os) {
os.close();
}
}
}
}
UDP实例 – 在线咨询
多线程 实现 双方交互
//发送类
public class TalkSend implements Runnable{
private DatagramSocket client ;
private String toIp;
private int toPort;
BufferedReader reader;
public TalkSend(int port, String toIp, int toPort){
this.toIp = toIp;
this.toPort = toPort;
client = new DatagramSocket(port);
reader = new BufferedReader(new InputStreamReader(System.in));
}
//重写
public void run(){
while(true){
//2.数据 封装
String data;
data = reader.readLine();
byte[] datas = data.getBytes();
//3.封装
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIp,this.toPort));
//4.发送
client.send(packet);
if(datas.equals("bye")){
break;
}
}
//5.释放资源
client.close();
}
}
//接收类
public class TalkReceive implements Runnable{
DatagramSocket server;
private String from;
public TalkReceive(int port, String from){
this.from = from;
server = new DatagramSocket(port);
}
public void run(){
while(true) {
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.
try {
server.receive(packet);
//4.数据处理分析
byte[] datas = packet.getData();
int len = packet.getLength();
String data = new String(datas,0,len);
System.out.println(from+":"+data);
if(datas.equals("bye")) {
break;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//5.释放资源
server.close();
}
}
TCP编程
简单测试
//服务端: 流程
1. 指定端口, 使用ServerSocket 创建服务端
2. 阻塞式等待连接accept
3. 操作:输入输出操作
4. 释放资源
public class Server {
public static void main(String[] args){
//1.指定端口 使用ServerSocket 创建服务端
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接 accept
Socket client = server.accept();
System.out.println("一个客户端建立连接");
//3.输出输入操作
DataInputStream dis = new DataInputStream(client.getInputStream());
String str = dis.readUTF();
System.out.println(str);
//4.释放资源
dis.close();
client.close();
server.close();
}
}
//客户端 : 流程
1.建立连接 : 使用Socket创建客户端 + 服务器地址和端口
2. 操作:输入输出
3. 释放资源
public class client{
public static void main(String[] args){
System.out.println("------------Client----------");
//1.建立连接
Socket client = new Socket("localhost",8888);
//2. 操作
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
String str = "Helloc";
dos.writeUTF(str);
dos.flush();
//3.释放资源
dos.close();
client.close();
}
}
网络登录功能分解
1.单向:客户端向服务器发送字符串,服务器获取字符串并输出
2.双向:服务器给客户端反馈,客户端得到反馈并输出。
3.文件:客户端向服务器端上传文件,服务器端获取文件并反馈结果
4.多线程:服务器端接收多个客户端的请求,并给出反馈 每个客户请求开启一个线程。
1.单向
/**
* 单向 : 服务端
* @author admin
*
*/
public class LoginServer {
public static void main(String[] args) throws IOException {
System.out.println("---------Server---------");
//1.创建
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接
Socket client = server.accept();
System.out.println("一个客户端建立连接");
//3.操作
DataInputStream dis = new DataInputStream(client.getInputStream());
String datas = dis.readUTF();
//分析
String[] dataArray = datas.split("&");
for(String info: dataArray) {
String[] userInfo = info.split("=");
if(userInfo[0].equals("uname")) {
System.out.println("你的用户名为:"+ userInfo[1]);
}else if(userInfo[0].equals("upwd")) {
System.out.println("你的密码为:"+ userInfo[1]);
}
}
//4.释放资源
dis.close();
client.close();
server.close();
}
}
/**
* 单向: 客户端
* @author admin
*
*/
public class LoginClient {
public static void main(String[] args) throws IOException {
System.out.println("--------Client--------");
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String uname = console.readLine();
System.out.println("请输入密码:");
String upwd = console.readLine();
//1.建立连接
Socket client = new Socket("localhost",8888);
//2.操作
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
dos.flush();
//3.释放资源
dos.close();
client.close();
}
}
双向
/**
* 双向模拟登录 -----客户端
* @author admin
*
*/
public class LoginTwoWayClient {
public static void main(String[] args) throws IOException {
System.out.println("-----Client-------");
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入你的用户名:");
String uname = console.readLine();
System.out.println("请输入你的密码:");
String upwd = console.readLine();
//1.建立连接
Socket client = new Socket("localhost",8888);
//2.操作
//写出
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("uname="+uname+"&"+"upwd=" + upwd);
dos.flush();
//接收
DataInputStream dis = new DataInputStream(client.getInputStream());
String result = dis.readUTF();
System.out.println(result);
//3.释放资源
dos.close();
dis.close();
client.close();
}
}
//双向模拟登录-----------服务端
public class LoginTwoWayServer {
public static void main(String[] args) throws IOException {
System.out.println("-------Server--------");
//1.创建
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待
Socket client = server.accept();
System.out.println("一个客户端建立连接");
//3.操作
//接收数据
DataInputStream dis = new DataInputStream(client.getInputStream());
String datas = dis.readUTF();
//
String uname = "";
String upwd = "";
String[] userArray = datas.split("&");
for(String info : userArray) {
String[] userInfo = info.split("=");
if(userInfo[0].equals("uname")){
System.out.println("你的用户名为:"+ userInfo[1]);
uname = userInfo[1];
}else if(userInfo[0].equals("upwd")) {
System.out.println("你的密码为:"+ userInfo[1]);
upwd = userInfo[1];
}
}
//发送
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
if(uname.equals("sxt") && upwd.equals("123")) {//成功
dos.writeUTF("登录成功");
}else {//失败
dos.writeUTF("登录失败");
}
dos.flush();
//4.释放资源
dis.close();
dos.close();
client.close();
server.close();
}
}
上传文件-----客户端
/**
* 上传文件
* @author admin
*
*/
public class FileClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---------Client--------");
//1.建立连接
Socket client = new Socket("localhost",8888);
//2.操作
InputStream is = new BufferedInputStream(new FileInputStream("src/copy.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();
//4.释放资源
os.close();
is.close();
client.close();
}
}
存储文件------服务端
/**
* 存储文件
* @author admin
*
*/
public class FileServer {
public static void main(String[] args) throws IOException {
System.out.println("-------Server-------");
//1.建立
ServerSocket server = new ServerSocket(8888);
//2。阻塞式等待接收连接
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
//3.操作:文件拷贝
InputStream is = new BufferedInputStream(client.getInputStream());
OutputStream os = new BufferedOutputStream(new FileOutputStream("src/tcp.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();
server.close();
}
}
多用户模拟登录
客户端
public class LoginMutilClient {
public static void main(String[] args) throws IOException {
System.out.println("------Client----------");
//1.建立连接
Socket client = new Socket("localhost",8888);
//2.操作
new Send(client).send();
new Receive(client).receive();
//释放资源
client.close();
}
//发送
static class Send{
private DataOutputStream dos ;
private Socket client;
private BufferedReader console ;
private String msg ;
public Send(Socket client) throws IOException {
console = new BufferedReader(new InputStreamReader(System.in));
this.client = client;
this.msg = init();
dos = new DataOutputStream(client.getOutputStream());
}
//初始化
private String init() throws IOException {
System.out.println("请输入你的用户名:");
String uname = console.readLine();
System.out.println("请输入你的用户名:");
String upwd = console.readLine();
return "uname="+uname+"&"+"upwd=" + upwd;
}
public void send() throws IOException {
dos.writeUTF(msg);
dos.flush();
}
}
//接收
static class Receive{
private DataInputStream dis ;
private Socket client;
public Receive(Socket client) throws IOException{
this.client = client;
dis = new DataInputStream(client.getInputStream());
}
public void receive() throws IOException {
String result = dis.readUTF();
System.out.println(result);
}
}
}
服务端
/**
* 多个客户端请求
* @author admin
*
*/
public class LoginMutilServer {
public static void main(String[] args) throws IOException {
System.out.println("---------Server----------");
//1.创建
ServerSocket server = new ServerSocket(8888);
boolean isRunning = true;
//2.等待连接
while(isRunning) {
Socket client = server.accept();
System.out.println("一个客户端建立连接");
new Thread(new Channel(client)).start();
}
server.close();
}
static class Channel implements Runnable{
private Socket client;
//输入流
private DataInputStream dis;
//输出流
private DataOutputStream dos;
public Channel(Socket client) throws IOException {
this.client = client;
//输入
try {
dis = new DataInputStream(client.getInputStream());
//输出
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
//释放
release();
}
}
//接收数据
private String receive() throws IOException{
String datas = "";
datas = dis.readUTF();
return datas;
}
//释放资源
private void release() throws IOException {
if(null != dos) {
dos.close();
}
if(null != dis) {
dis.close();
}
if(null != client) {
client.close();
}
}
//发送数据
private void send(String msg) throws IOException {
dos.writeUTF(msg);
dos.flush();
}
@Override
public void run() {
String uname = "";
String upwd = "";
//分析
try {
String[] dataArray = receive().split("&");
for(String info : dataArray) {
String[] useInfo = info.split("=");
if(useInfo[0].equals("uname")) {
System.out.println("你的用户名为:" + useInfo[1]);
uname = useInfo[1];
}else if(useInfo[0].equals("upwd")) {
System.out.println("你的密码为:" + useInfo[1]);
upwd = useInfo[1];
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//发送
if(uname.equals("sxt") && upwd.equals("123")) {
try {
send("登录成功");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
try {
send("登录失败");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
聊天室
服务端:一个线程专门发消息 一个线程专门收消息
客户端: 一个线程专门发消息 一个线程专门收消息
一:目标 : 实现一个用户正常收发消息
/**
* 在线聊天室 : 客户端
* 目标: 实现一个客户端可以正常收发消息
* @author admin
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---------Server---------");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入信息:");
String msg = reader.readLine();
//1.建立连接 利用Socket + 服务的IP 和 端口
Socket client = new Socket("localhost",8888);
//2.操作
//发
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(msg);
dos.flush();
//获取消息
DataInputStream dis = new DataInputStream(client.getInputStream());
String result = dis.readUTF();
System.out.println(result);
//3.释放资源
dos.close();
client.close();
}
}
/**
* 在线聊天室: 服务端
* 目标: 实现一个客户正常收发消息
* @author admin
*
*/
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();
//返回消息
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(msg);
dos.flush();
//4.释放资源
dis.close();
client.close();
server.close();
}
}
二:收发多条消息
在收发消息处加个循环就好 另外注意客户端读取键盘输入 加到 循环里
还有 循环条件最好整个变量 , 不然会报错—“unreachable code”
/**
* 在线聊天室: 服务端
* 目标: 实现一个客户多次正常收发消息
* @author admin
*
*/
public class MutilTalkChat {
public static void main(String[] args) throws IOException {
System.out.println("----------Server---------");
//1.创建
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接
Socket client = server.accept();
System.out.println("一个客户端 建立连接");
//3.操作
//接收消息
boolean isRunning = true;
DataInputStream dis = new DataInputStream(client.getInputStream());;
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
while(isRunning) {
String msg = dis.readUTF();
//发消息
dos.writeUTF(msg);
dos.flush();
}
//4.释放资源
dis.close();
client.close();
server.close();
}
}
/**
* 在线聊天室 : 客户端
* 目标: 实现一个客户端可以多次正常收发消息
* @author admin
*
*/
public class MutilTalkClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---------Server---------");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入信息:");
//1.建立连接
Socket client = new Socket("localhost",8888);
//2.操作
boolean isRunning = true;
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
DataInputStream dis = new DataInputStream(client.getInputStream());
while(isRunning) {
//发消息
String msg = reader.readLine();
dos.writeUTF(msg);
dos.flush();
//获取消息
String result = dis.readUTF();
System.out.println(result);
}
//释放资源
dos.close();
dis.close();
client.close();
}
}
三:多个客户 同时 收发多条消息
1.首先对服务端 使用多线程并进行封装
/**
* 服务端
* 使用多线程 封装 : 实现多个用户发送多条消息
* @author admin
*
*/
public class MultiChat {
public static void main(String[] args) throws IOException {
System.out.println("----------Server---------");
//1.创建
ServerSocket server = new ServerSocket(9999);
//2.阻塞式等待连接
while(true){
Socket client = server.accept();
System.out.println("一个客户端 建立连接");
//3.操作
new Thread(new Channel(client)).start();
}
}
}
//一个客户 一个channel
class Channel implements Runnable{
DataInputStream dis = null;
DataOutputStream dos =null;
private Socket client;
private boolean isRunning ;
public Channel(Socket client) throws IOException {
this.client = client;
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
isRunning = true;
}
//发消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("------发——————--");
release();
}
}
//收消息
private String receive() {
String msg1 = "";
try {
msg1 = dis.readUTF();
} catch (IOException e) {
System.out.println("------收——————--");
release();
}
return msg1;
}
//释放资源
private void release() {
this.isRunning = false;
UtilsRealease.close(dis,dos,client);
}
@Override
public void run() {
while(isRunning) {
//先读
String msg = this.receive();;
//写
if(!msg.equals(""))
send(msg);
}
}
}
2.客户端 为了解决 客户端只能 先写 后读的问题,应该用多线程 并进行封装
客户端
/**
* 客户端
* 使用多线程 封装 : 实现多个用户发送多条消息
* @author admin
*
*/
public class MultiClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---------Clien---------");
System.out.println("请输入信息:");
//1.建立连接
Socket client = new Socket("localhost",9999);
//2.操作
new Thread(new Send(client)).start();
new Thread(new Receive(client)).start();
}
}
发送端
/**
* 发送
* @author admin
*
*/
public class Send implements Runnable{
private BufferedReader reader ;
private boolean isRunning = true;
private DataOutputStream dos;
private Socket client;
public Send(Socket client) throws IOException {
this.client = client;
reader = new BufferedReader(new InputStreamReader(System.in));
isRunning = true;
dos = new DataOutputStream(client.getOutputStream());
}
//从控制台获取消息
private String getConsoleInform() {
try {
return reader.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
release();
}
}
//重写
public void run() {
while(isRunning) {
String msg = getConsoleInform();
if(!msg.equals("")) {
send(msg);
}
}
}
//释放资源
public void release() {
this.isRunning = false;
UtilsRealease.close(dos,client);
}
}
//接收端
/**
* 收消息
* @author admin
*
*/
public class Receive implements Runnable{
private boolean isRunning;
private Socket client;
private DataInputStream dis = null;
public Receive(Socket client) throws IOException {
this.client = client;
dis = new DataInputStream(client.getInputStream());
isRunning = true;
}
//收消息
private String receive() {
String msg ="";
try {
msg = dis.readUTF();
return msg;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
public void run() {
while(isRunning) {
String msg = receive();
if(!msg.equals(""))
System.out.println(msg);
}
}
//释放资源
private void release() {
this.isRunning = false;
UtilsRealease.close(dis,client);
}
}
**
群聊
加入容器 实现群聊 容器:CopyOnWriteArrayList
**
服务端
/**
* 服务端
* 群聊
* @author admin
*
*/
public class Chat {
public static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<Channel>();
public static void main(String[] args) throws IOException {
System.out.println("----------Server---------");
//1.创建
ServerSocket server = new ServerSocket(9999);
//2.阻塞式等待连接
while(true){
Socket client = server.accept();
System.out.println("一个客户端 建立连接");
Channel c = new Channel(client);
all.add(c);
//3.操作
new Thread(c).start();
}
}
//一个客户 一个channel
static class Channel implements Runnable{
DataInputStream dis = null;
DataOutputStream dos =null;
private Socket client;
private boolean isRunning ;
private String name;
public Channel(Socket client) throws IOException {
this.client = client;
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
isRunning = true;
//获取名称
this.name = receive();
//欢迎
this.send("欢迎您的到来");
sendOthers(this.name+ "--来到了直播间",true); //系统消息
}
//发消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("------发——————--");
release();
}
}
//群聊
private void sendOthers(String msg,boolean isSys) {
for(Channel other : all) {
if(other == this) { //自身
continue;
}
if(!isSys) {
other.send(this.name+ "对所有人说:" + msg);
}else {
other.send(msg); //系统消息
}
}
}
//收消息
private String receive() {
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
System.out.println("------收——————--");
release();
}
return msg;
}
//释放资源
private void release() {
this.isRunning = false;
UtilsRealease.close(dis,dos,client);
//退出
all.remove(this);
sendOthers(this.name + "离开了",true);
}
@Override
public void run() {
while(isRunning) {
//先读
String msg = this.receive();;
//写
if(!msg.equals(""))
//send(msg);
sendOthers(msg,false);
}
}
}
}
客户端
除了加了个姓名(加到构造器上) 别的无变化
私聊
自己约定个格式,然后发送
只对服务端 的 群聊发送消息的函数 进行修改就行了
//群聊
//私聊 :约定格式 : @XXX:msg
private void sendOthers(String msg,boolean isSys) {
boolean isPrivate = msg.startsWith("@");
if(isPrivate) { //私聊
int index = msg.indexOf(":");
//获取数据
String targetName = msg.substring(1,index);
msg = msg.substring(index+1);
for(Channel c : all) {
if(c.name.equals(targetName)) { //目标对象
c.send(this.name + "悄悄的对您说"+ msg);
}
}
}else {
for(Channel other : all) {
if(other == this) { //自身
continue;
}
if(!isSys) {
other.send(this.name+ "对所有人说:" + msg);
break;
}else {
other.send(msg); //系统消息
}
}
}
}