package SocketDemo;
import java.net.InetSocketAddress;
/*
*
* 套接字:
* 进行网络数据传输的一套API,本质上可以在网络上使用的流
*
* 1.网络基本概念:
* 1.1七层模型:物理层,数据链路层,网络层,传输层(UDP/TCP),会话层,应用层,表示层--HTTP,FTP,POP3,SMTP
*
* 1.2IP地址:在网络中标记主机。
* IPv4:四组数表示一个IP地址 196.120.30.200 每一组数取值范围是0-255 2^8
* IPv6:六组数表示一个IP地址
* IPv9:
*
* 1.3 端口:计算机与外界交互的媒介。 端口号:0~65535 熟知端口号0-1024 客户端端口号:1025-65535
*
* 1.4域名:各个网站所提供的便于记忆的标记。 www.baidu.com
* DNS:域名解析系统,将域名和IP进行对应。
*/
public class SocketDemo01 {
public static void main(String[] args) {
//1.根据 IP地址和端口号创建套接字地址。InetSocketAddress(InetAddress addr, int port)
//"localhost"表示本机,127.0.0.1表示本机这个地址不可变。
InetSocketAddress isa=new InetSocketAddress("www.baidu.com",8080);
//2.获取地址 .getAddress()
System.out.println(isa.getAddress()); //输出www.baidu.com/183.232.231.173
//3.获取主机名/域名 .getHostName()
//注意:如果输入的地址是本机地址,那么返回的是计算机的主机名
System.out.println(isa.getHostName()); //输出www.baidu.com
//4.获取端口号 .getPort()
System.out.println(isa.getPort()); //输出8080
}
}
package SocketDemo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
/*
* *2.UDP
*
* 特点:
* 底层基于流使用,不建立连接,不可靠,传输速度是相对比较快的。
* 需要对数据进行封包,每个包不超过64K大小。
*
* 适用:
* 适用于对速度依赖性比较强但是对可靠性依赖性比较低的场景。 ---视频,直播
*
*
*3. DatagramSocket DatagramPacket
* 先运行接收端,后进行发送端,接收端多个数据包的5.解析数据
*
* 发送端:1.创建UDP套接字对象 ds=DatagramSocket()
* 2.准备数据包,并且将数据放入数据包中,并且绑定要发往的地址 dp=DatagramPacket(buf,length,address)
* 3.发送数据包 ds.send(dp)
* 4.关流 ds.close()
*
*
* 接收端: 1.创建UDP套接字对象,并绑定端口号 ds=DatagramSocket(Port);
2. 准备数据包 dp=DatagramPacket(byte[] buf, int length)
3. 接收数据 ds.receive(dp);
4. 关流 ds.close();
5. 解析数据 数据包的底层数组byte[] bs=dp.getData();
数据的实际大小int len=dp.getLength();
new String(bs,0,len);
*
*
*/
//UDP发送端
public class SocketDemo02UDPSend {
public static void main(String[] args) throws IOException {
//1.创建一个UDP套接字对象 new DatagramSocket();
DatagramSocket ds=new DatagramSocket();
//2.准备数据包,并且将数据放入数据包 new DatagramPacket(buf.length,address);
//buf:表示要发送的数据
//length:表示发送的数据大小
//address:表示要发送的地址
DatagramPacket dp=new DatagramPacket("你好".getBytes(), "你好".getBytes().length, new InetSocketAddress("localhost",8080));
//3.发送数据包 .send()
ds.send(dp);
//4.关流 .close()
ds.close();
}
}
package SocketDemo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
//UDP接收,先运行接收端,后进行发送端,接收端多个数据包的5.解析数据
/*
*3. DatagramSocket DatagramPacket
* 先运行接收端,后进行发送端
*
* 发送端:1.创建UDP套接字对象 ds=DatagramSocket()
* 2.准备数据包,并且将数据放入数据包中,并且绑定要发往的地址 dp=DatagramPacket(buf,length,address)
* 3.发送数据包 ds.send(dp)
* 4.关流 ds.close()
*
*
* 接收端: 1.创建UDP套接字对象,并绑定端口号 ds=DatagramSocket(Port);
2. 准备数据包 dp=DatagramPacket(byte[] buf, int length)
3. 接收数据 ds.receive(dp);
4. 关流 ds.close();
5. 解析数据 数据包的底层数组byte[] bs=dp.getData();
数据的实际大小int len=dp.getLength();
new String(bs,0,len);
*
*/
//UDP接收端
public class SocketDemo02UDPReceive {
public static void main(String[] args) throws IOException {
//1.创建一个UDP套接字对象,绑定端口号 new DatagramSocket(port);
DatagramSocket ds=new DatagramSocket(8080);
//2.用来接收长度为length的数据包。 DatagramPacket(byte[] buf, int length)
DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
//3.接收数据 .receive()
ds.receive(dp);
System.out.println("接收成功");
//4.关流 .close()
ds.close();
//5.将数据从数据包中解析出来
//5.1获取数据包的底层数组
byte[] bs=dp.getData();
//5.2获取数据的实际大小
int len=dp.getLength();
System.out.println(new String(bs,0,len));
//获取发送过来的主机地址
System.out.println(dp.getAddress());
//获取发送过来的端口号
System.out.println(dp.getPort());
}
}
package SocketDemo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class SocketUDPExer {
public static void main(String[] args) {
//练习1:一个线程表示发送端,另一个线程表示接收端---单人聊天
new Thread(new UDPSend()).start();
new Thread(new UDPReceive()).start();
}
}
/*
* 发送端: 1.创建UDP套接字对象 ds=DatagramSocket()
* 2.准备数据包,并且将数据放入数据包中,并且绑定要发往的地址 dp=DatagramPacket(buf,length,address)
* 3.发送数据包 ds.send(dp)
* 4.关流 ds.close()
*/
//发送端
class UDPSend implements Runnable{
private DatagramSocket ds;
private DatagramPacket dp;
private Scanner s;
//构造代码块
{
try {
//1.创建UDP套接字对象 ds=DatagramSocket()
ds=new DatagramSocket();
//写入数据
s=new Scanner(System.in);
}catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
//读取数据
String msg=s.nextLine();
byte[] bs=msg.getBytes();
//2.准备数据包,并且将数据放入数据包中,并且绑定要发往的地址 dp= DatagramPacket(buf,length,address)
//改为255.255.255.255广播地址 可以多人聊天
dp=new DatagramPacket(bs,bs.length,new InetSocketAddress("localhost",8080));
try {
//3.发送数据包 ds.send(dp)
ds.send(dp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
// 4.关流 ds.close()
ds.close();
}
}
}
}
/*
* 接收端: 1.创建UDP套接字对象,并绑定端口号 ds=DatagramSocket(Port);
2. 准备数据包 dp=DatagramPacket(byte[] buf, int length)
3. 接收数据 ds.receive(dp);
4. 关流 ds.close();
5. 解析数据 数据包的底层数组byte[] bs=dp.getData();
数据的实际大小int len=dp.getLength();
new String(bs,0,len);
*/
class UDPReceive implements Runnable{
private DatagramSocket ds;
//---------为什么这里可以直接创建--------------
//2.用来接收长度为length的数据包。 DatagramPacket(byte[] buf, int length)
private DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
{
try {
//1.创建一个UDP套接字对象,绑定端口号 new DatagramSocket(port);
ds=new DatagramSocket(8080);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
while(true) {
//3.接收数据 .receive()
ds.receive(dp);
//5.将数据从数据包中解析出来
//5.1获取数据包的底层数组 byte[] bs=dp.getData();
//5.2获取数据的实际大小 int len=dp.getLength();
System.out.println(dp.getAddress()+":");
byte[] bs=dp.getData();
int len=dp.getLength();
System.out.println(new String(bs,0,len));
//等价于System.out.println(new String(dp.getData,0,dp.getLength()));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//4.关流 .close()
ds.close();
}
}
}
package SocketDemo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/*
*3. TCP
*
* 基于流的,建立连接,经历三次握手,可靠,但是传输速率相对较慢,理论上不限制传输的数据的大小。
适用于对可靠性的依赖性更高对速度依赖性较低的场景----文件传输
*
* 3.1三次握手;
* 1.请求: 建立连接/发送数据 ->
* 客户端 <- 2.确认: 可以建立连接/发送数据 服务器
* 3.再次确认: 收到信息,准备连接/发送 ->
*
*
* 3.1注意:receive / connect/accept/write/read 都会产生阻塞
* 扩展:BIO Blocking IO 同步式阻塞式IO
* NIO New IO-NonBlock IO 同步式非阻塞式IO JDK1.4
* AIO Asynchronous IO 异步式非阻塞式IO JDK1.8
*
*/
/*
* TCP客户端:Socket
* 1.创建客户端的套接字对象sc=Socket()
* 2.发起连接 sc.connect()
* 3.获取自带的输出流,写数据,写完禁用输出流
* OutputStream out=sc.getOutputStream() out.write(byte[]) sc.shutdownOutput();
* 4.如果服务器端游打回的数据,需要获取输入流读取数据,禁用输入流
* InputStream in=sc.getInputStream(); in.read(byte[]) sc.shutdownInput();
* 5.关流 sc.close()
*
*
*
* TCP服务端:ServerSocket
* 1.创建服务器端的套接字对象,并且绑定监听的端口号 ss=ServerSocket(port)
* 2.接受连接,获取到一个Socket对象 Socket s=ss.accept()
* 3.获取输入流,读取消息,读完禁用输入流
* InputStream in=s.getInputStream(); in.read(byte[]) s.shutdownInput();
* 4.如果需要向客户端发送消息,则需要获取输出流数据,禁用输出流
* s.getOutputStream().write("消息读取成功".getBytes()); s.shutdownOutput();
* 5.关流 ss.close();
*/
public class SocketDemo03TCPClient {
public static void main(String[] args) throws IOException {
//1.创建客户端的套接字对象 sc=Socket()
Socket sc=new Socket();
//2.发起连接 sc.connect(Address) //手动阻塞时间,5秒钟连接不上,就拒绝连接
sc.connect(new InetSocketAddress("localhost",8005),5000);
//3.1获取Socket上的输出流
OutputStream out= sc.getOutputStream();
//3.2向服务器发送数据
out.write("你好".getBytes());
//3.3告诉服务器数据已经写出完毕
sc.shutdownOutput();
//4.接受服务器打回的消息
InputStream in=sc.getInputStream();
byte[] bs=new byte[1024];
int len=-1;
while((len=in.read(bs))!=-1) {
System.out.println(new String(bs,0,len));
}
sc.shutdownInput();
//5.关流
sc.close();
}
}
package SocketDemo;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* TCP客户端:Socket
* 1.创建客户端的套接字对象sc=Socket()
* 2.发起连接 sc.connect()
* 3.获取自带的输出流,写数据,写完禁用输出流
* OutputStream out=sc.getOutputStream() out.write(byte[]) sc.shutdownOutput();
* 4.如果服务器端游打回的数据,需要获取输入流读取数据,禁用输入流
* InputStream in=sc.getInputStream(); in.read(byte[]) sc.shutdownInput();
* 5.关流 sc.close()
*
*
*
* TCP服务端:ServerSocket
* 1.创建服务器端的套接字对象,并且绑定监听的端口号 ss=ServerSocket(port)
* 2.接受连接,获取到一个Socket对象 Socket s=ss.accept()
* 3.获取输入流,读取消息,读完禁用输入流
* InputStream in=s.getInputStream(); in.read(byte[]) s.shutdownInput();
* 4.如果需要向客户端发送消息,则需要获取输出流数据,禁用输出流
* s.getOutputStream().write("消息读取成功".getBytes()); s.shutdownOutput();
* 5.关流 ss.close();
*/
public class SocketDemo03TCPServer {
public static void main(String[] args) throws IOException {
//1.创建服务器端的套接字对象,绑定端口号
ServerSocket ss=new ServerSocket(8005);
//2.接受连接
//产生阻塞
Socket s=ss.accept();
//3.1获取Socket自带的输入流
InputStream in=s.getInputStream();
//3.2读取客户端发来的数据
byte[] bs=new byte[1024];
int len=-1;
while((len=in.read(bs))!=-1) {
System.out.println(new String(bs,0,len));
}
//3.3通知客户端数据读取完毕
s.shutdownInput();
//4.向客户端打回一条消息
s.getOutputStream().write("消息读取成功".getBytes());
s.shutdownOutput();
//5.关流
ss.close();
}
}
package SocketDemo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
//练习1.采用TCP上传文件
//客户端读取文件并将读取的内容传到服务器端
//在服务器端接收数据然后将接收的数据写到相应文件
/*
* TCP客户端:Socket
* 1.创建客户端的套接字对象sc=Socket()
* 2.发起连接 sc.connect()
* 3.获取自带的输出流,写数据,写完禁用输出流
* OutputStream out=sc.getOutputStream() out.write(byte[]) sc.shutdownOutput();
* 4.如果服务器端游打回的数据,需要获取输入流读取数据,禁用输入流
* InputStream in=sc.getInputStream(); in.read(byte[]) sc.shutdownInput();
* 5.关流 sc.close()
*
*
*/
/*
* 如果文件名的字节个数超过了一个字节所能表示的范围,那么这个时候可以用2个字节传输所表示文件名的字节个数
byte n = (byte)(len / 256); // 确定文件名中有几个完整的字节
byte left = (byte)(len % 256 - 128); // 去掉完整字节之后的剩余的可以传输的字节个数
读取的时候通过
int len = n * 256 + left + 128; 从而表示完整的全部文件名占用的字节个数
*/
public class SocketTCPExerClient {
public static void main(String[] args) throws IOException {
//1.创建客户端的套接字对象
Socket sc=new Socket();
//2.发起连接 //手动阻塞时间,5秒钟连接不上,就拒绝连接
sc.connect(new InetSocketAddress("localhost",8010),5000);
//3.获取Socket上的输出流
OutputStream out= sc.getOutputStream();
//-----------只需要改这一步-----------之前是out.write("你好".getBytes());-----------------
//4.向服务器发送数据
//4.1获取文件的名字和类型,并写出
File file=new File("C:\\Users\\123\\Desktop\\0317笔记.docx");
byte[] filename =file.getName().getBytes();
out.write(filename.length-128); //先写文件名长度 9 00001001 26 00011001 可以一个字节表示文件名长度
out.write(filename); //再写文件名
//4.2读取文件内容,并写出
FileInputStream in2=new FileInputStream(file);
byte[] bytes=new byte[10];
int length=-1;
while((length=in2.read(bytes))!=-1) {
out.write(bytes,0,length);
}
in2.close();
//5.告诉服务器数据已经写出完毕
sc.shutdownOutput();
//6.关流
sc.close();
}
}
package SocketDemo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/* TCP服务端:ServerSocket
* 1.创建服务器端的套接字对象,并且绑定监听的端口号 ss=ServerSocket(port)
* 2.接受连接,获取到一个Socket对象 Socket s=ss.accept()
* 3.获取输入流,读取消息,读完禁用输入流
* InputStream in=s.getInputStream(); in.read(byte[]) s.shutdownInput();
* 4.如果需要向客户端发送消息,则需要获取输出流数据,禁用输出流
* s.getOutputStream().write("消息读取成功".getBytes()); s.shutdownOutput();
* 5.关流 ss.close();
*/
/*
* 如果文件名的字节个数超过了一个字节所能表示的范围,那么这个时候可以用2个字节传输所表示文件名的字节个数
byte n = (byte)(len / 256); // 确定文件名中有几个完整的字节
byte left = (byte)(len % 256 - 128); // 去掉完整字节之后的剩余的可以传输的字节个数
读取的时候通过
int len = n * 256 + left + 128; 从而表示完整的全部文件名占用的字节个数
*/
public class SocketTCPExerServer {
public static void main(String[] args) throws IOException {
//1.创建服务器端的套接字对象,绑定端口号
ServerSocket ss=new ServerSocket(8010);
//2.接受连接
//产生阻塞
Socket s=ss.accept();
//3.获取Socket自带的输入流
InputStream in=s.getInputStream();
//-----------只需要改这一步--------------------
/*
* 之前是
* byte[] bs=new byte[1024];
int len=-1;
while((len=in.read(bs))!=-1) {
System.out.println(new String(bs,0,len));
}
*/
//4.读取客户端发来的数据
//读取文件名的长度
byte len=(byte)in.read(); //先读一次,就读一个字节,读取文件名长度
byte[] name=new byte[len+128]; //文件名长度为每次读取的长度
in.read(name); //再读一次,读取文件名
FileOutputStream out2=new FileOutputStream("C:\\Users\\123\\Tarena\\"+new String(name));
byte[] bs2=new byte[1024];
int len2=-1;
while((len2=in.read(bs2))!=-1) {
out2.write(bs2,0,len2);
}
out2.close();
//5.通知客户端数据读取完毕
s.shutdownInput();
//6.关流
ss.close();
}
}
package JDK5;
/*
* JDK1.5的特性
1.自动封箱/拆箱
2.增强for循环
3.静态导入
4.可变参数
5.枚举
6.泛型
7.反射(JDK1.4出现,1.5增强)
8. 动态代理
9.内省
10.注解
*/
//可变参数 ...
//1.可变参数,允许传入的参数个数随意变换
//2.可变参数本质上是数组 int... is=int[] is
//3.可变参数可以传入0-多个参数
//4.一个方法中只能定义一个可变参数,这唯一的一个可变参数必须定义到参数列表的末尾
public class VariableDemo {
public static void main(String[] args) {
//System.out.println(add(new int[] {2,4,6,5,8}));
//任意数目的数字求和
//3.可变参数可以传入0-多个参数
System.out.println(add()); //不传值是0,默认为0
System.out.println(add(6));
System.out.println(add(6,8));
System.out.println(add(6,8,98,9,6,5,6,8,9,4));
}
//1.可变参数,允许传入的参数个数随意变换
public static int add(int... is) { //4.一个方法中只能定义一个可变参数,这唯一的一个可变参数必须定义到参数列表的末尾
int sum=0;
for(int i=0;i<is.length;i++) { //2.可变参数本质上是数组 int... is=int[] is
sum+=is[i];
}
return sum;
}
/*
//注意:2个整数和3个整数求和代码与10个数组功能冗余。
//2个整数求和
public static int add(int i,int j) {
return i+j;
}
//3个整数求和
public static int add(int i,int j,int k) {
return i+j+k;
}
//10个整数求和
public static int add(int[] arr) {
int sum=0;
for(int i:arr) {
sum+=i;
}
return sum;
}
*/
}
package JDK5;
/*
* JDK1.5的特性
1.自动封箱/拆箱
2.增强for循环
3.静态导入
4.可变参数
5.枚举
6.泛型
7.反射(JDK1.4出现,1.5增强)
8. 动态代理
9.内省
10.注解
*/
//5.枚举 ---------没写完--------------
// 1.取值相对固定并且能够一一列举。
// 2.用enum定义枚举,枚举本身就是一个类
// 3.枚举类中的构造方法默认私有,枚举常量必须定义在枚举类的首行
// 4.枚举类中定义任意类型的方法和属性,包括抽象方法
//
// 5.在Java中,所有的枚举默认继承java.lang.Enum
// 6.JDK1.5开始,允许在switch-case中使用枚举常量
public class EnumDemo {
public static void main(String[] args) {
Seasons s=Seasons.Spring;
//s.say();
//6.JDK1.5中,允许在switch-case中使用
switch(s) {
case Spring:
System.out.println("春天");
break;
case Summer:
System.out.println("夏天");
break;
case Autumn:
System.out.println("秋天");
break;
case Winter:
System.out.println("冬天");
break;
default :
break;
}
}
}
//枚举,本身是类
enum Seasons{
//3.枚举中的构造方法默认私有化 private Seasons(){}
Spring,Summer,Autumn,Winter;//3.枚举常量,且必须定义定义在枚举类的首行
//4.可以在枚举类提供任意属性和方法
private int[] months;
private int year;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
//4.可以定义抽象方法,只是枚举常量变为匿名内部类
/*
//构造方法可以重载
private int year;
private Seasons() {
}
private Seasons(int year) {
this.year = year;
}
public abstract void Say() {
System.out.println("抽象方法");
}
将枚举常量变为匿名内部类
Sping(256){ //构造方法重载传入参数
@Override
public void Say() {
// TODO Auto-generated method stub
}
};
*/
}
//无枚举之前
class Season{
private Season() {}
public static final Season Spring=new Season();
public static final Season Summer=new Season();
public static final Season Autumn=new Season();
public static final Season Winter=new Season();
}