网络编程(套接字)
通过Java程序实现网络之间的数据传输 底层基于网络来传输的流
网络模型
ip地址
确定在网络中的位置 IPv4 由四位0-255之间的数组成的 10.34.8.10 IPv6
端口
计算机和外部进行数据交互的媒介—端口号(0-65535)
0-1024这些端口号大部分已经被系统占用,自己使用端口号的时候就从1025往后找
www.baidu.com 域名
通过DNS可以映射到对应的IP
SocketAddress 代表IP地址的类
package cn.tedu.inernet;
import java.net.InetSocketAddress;
/**
*@author 作者:
*@version 创建时间:2020年11月22日下午8:33:39
*@description 描述:
*/
public class InetSocketAddressDemo {
public static void main(String[] args) {
//表示IP和端口的对象
//127.0.0.1这个IP一直指向本地
//localhost和127.0.0.1互相映射
//InetSocketAddress isa=new InetSocketAddress("www.baidu.com", 8090);
//InetSocketAddress isa=new InetSocketAddress("192.168.199.140", 8090);
//InetSocketAddress isa=new InetSocketAddress("127.0.0.1", 8090);
InetSocketAddress isa=new InetSocketAddress("localhost", 8090);
//获取IP地址
System.out.println(isa.getAddress());
//获取主机名
System.out.println(isa.getHostName());
//获取端口号
System.out.println(isa.getPort());
}
}
UDP 底层基于流,不会建立连接,不可靠,但是传输速度快
底层是经过数据包来进行数据的传输,数据包大小一般不能超过64kb
适用场景:视频聊天等–DatagramSocket、DatagramPacket
package cn.tedu.inernet.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
/**
*@author 作者:
*@version 创建时间:2020年11月22日下午10:21:51
*@description 描述:发送端
*/
public class UDPSenderDemo {
public static void main(String[] args) throws IOException {
//创建套接字对象
DatagramSocket ds=new DatagramSocket();
//创建待传输数据包
//第一个参数要传输数据的字节数组
//第二个参数真正要发送数据的长度(最大和数组长度一致)
//第三个参数指明要传输的IP地址和端口号
DatagramPacket dp=new DatagramPacket("你好".getBytes(), "你好".getBytes().length, new InetSocketAddress("127.0.0.1", 8009));
//发送数据包
ds.send(dp);
//关流---底层是字节流
ds.close();
}
}
package cn.tedu.inernet.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
*@author 作者:
*@version 创建时间:2020年11月22日下午10:30:33
*@description 描述:接收端
*/
public class UDPReceiverDemo {
public static void main(String[] args) throws IOException {
//创建套接字对象--绑定端口号
DatagramSocket ds=new DatagramSocket(8009);
//创建数据包用来接受数据---第二个参数代表实际接受数据的长度
DatagramPacket dp=new DatagramPacket(new byte[1024], 1024);
//接受数据把数据存放到数据包
//阻塞
ds.receive(dp);
//关流
ds.close();
//解析数据包
//dp.getData()---获取数据
//dp.getLength()---获取长度
System.out.println(new String(dp.getData(),0,dp.getLength()));
//获取IP地址和端口号
System.out.println(dp.getAddress());
System.out.println(dp.getPort());
}
}
发送端
1、创建套接字对象
2、创建需要发送的数据包(指定要发送的数据的长度以及IP地址和端口号)
3、发送数据包
4、关流
接收端
1、创建套接字对象(绑定具体的端口号)
2、创建需要接受的数据包(指定真实接受数据的长度)
3、接收数据包
4、关流
5、解析数据包
案例:
1、通过UDP来实现简易的聊天室(线程)
package cn.tedu.inernet.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
/**
*@author 作者:
*@version 创建时间:2020年11月22日下午11:08:14
*@description 描述:简易的聊天(线程)
*/
public class UDPChatDemo {
public static void main(String[] args) {
//开启线程
new Thread(new Sender()).start();
new Thread(new Receiver()).start();
}
}
//发送端--线程
class Sender implements Runnable{
//声明对象
DatagramSocket ds;
Scanner sc;
@Override
public void run() {
// TODO Auto-generated method stub
//对象的初始化
try {
ds=new DatagramSocket();
sc=new Scanner(System.in);
while(true) {//保证一直写数据发送数据
//录入信息
byte[] bs=sc.nextLine().getBytes();
//创建发送的数据包
DatagramPacket dp=new DatagramPacket(bs, bs.length,new InetSocketAddress("127.0.0.1", 8090));
//发送数据包
ds.send(dp);
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//接收端
class Receiver implements Runnable{
//声明对象
DatagramSocket ds;
DatagramPacket dp;
@Override
public void run() {
// TODO Auto-generated method stub
//对象初始化
try {
ds=new DatagramSocket(8090);
dp=new DatagramPacket(new byte[1024], 1024);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(true) {
//接受数据包
try {
ds.receive(dp);
//解析数据包
System.out.println(new String(dp.getData(),0,dp.getLength()));
System.out.println(dp.getAddress());
System.out.println();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
TCP三次握手
TCP
底层基于流,建立链接,可靠,传输速度慢
TCP通过字节流直接传输数据不需要数据包,就没有传输数据的限制
适用场景:传输文件,下载电影等
客户端
1、建立TCP客户端对象
2、发起链接(指明要发送的ip和端口)
3、获取自带的字节输出流
4、根据自带的字节输出流往服务端写出数据
5、通知服务器已经写完、关流
服务器端
1、创建TCP服务器端对象
2、接受链接
3、获取自带的字节流
4、通过自带的字节进行数据读取
5、通知客户端已经读取完、关流
package cn.tedu.inernet.tcp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
*@author 作者:
*@version 创建时间:2020年11月27日下午2:22:21
*@description 描述:客户端
*/
public class TCPClientDemo {
public static void main(String[] args) throws IOException {
//创建TCP的套接字
Socket s=new Socket();
//发起链接----指定链接的IP和端口
//阻塞---服务器不接受链接阻塞报错
s.connect(new InetSocketAddress("127.0.0.1", 8010));
/*//证明写有无阻塞
OutputStream os=s.getOutputStream();
for (int i = 0; i < 1000000000; i++) {
os.write("abc".getBytes());
System.out.println(i);//没有全输完说明写也有阻塞
}*/
//while(true);
//获取自带的字节输出流
//写出的数据默认往服务器里边写
OutputStream os=s.getOutputStream();
//通过自带的字节输出流写数据
os.write("服务器你好...".getBytes());
//通知服务器数据已写完
s.shutdownOutput();
//获取自带的字节输入流
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));
}
//通知服务器端数据已读完
s.shutdownInput();
//关流
os.close();
in.close();
}
}
package cn.tedu.inernet.tcp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
*@author 作者:
*@version 创建时间:2020年11月27日下午2:32:00
*@description 描述:服务器
*/
public class TCPServerDemo {
public static void main(String[] args) throws IOException {
//创建tcp服务器端对象----绑定端口
ServerSocket ss=new ServerSocket(8010);
//接受链接
//阻塞
Socket s=ss.accept();
//while(true);
//System.out.println(1);//光运行服务器没有输出1说明接受阻塞;运行完服务运行客户机输出1说明服务器读取阻塞
//读取传过来的数据
//获取自带的输入流
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));
}
//通知客户端数据已读完
s.shutdownInput();
//获取自带的字节输出流
OutputStream os=s.getOutputStream();
//往客户端写数据
os.write("你也好".getBytes());
//通知客户端数据已经写完
s.shutdownOutput();
//关流
os.close();
//关流
in.close();
}
}
receive、connect、accept、write、read都有阻塞存在
TCP实现文件的复制
package cn.tedu.inernet.tcp;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
*@author 作者:
*@version 创建时间:2020年11月27日下午4:54:00
*@description 描述:
*/
public class TCPFileCopyClient {
public static void main(String[] args) throws IOException {
//创建TCP客户端对象
Socket s=new Socket();
//发起链接
s.connect(new InetSocketAddress("127.0.0.1", 9009));
//创建文件类对象
File file=new File("D:\\a\\1.mp4");
//把外部文件读取进来
FileInputStream fis=new FileInputStream(file);
//获取自带的输出流
OutputStream os=s.getOutputStream();
//获取文件的名称,长度
//先传文件的长度
//os.write(file.getName().length());
os.write(file.getName().length()-128);
//传文件的内容
os.write(file.getName().getBytes());
byte[] bs=new byte[1024*1024*10];
int len=-1;
while((len=fis.read(bs))!=-1){
//往服务端写数据
os.write(bs,0,len);
}
//通知服务端已写完
s.shutdownOutput();
//关流
fis.close();
os.close();
}
}
package cn.tedu.inernet.tcp;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
*@author 作者:
*@version 创建时间:2020年11月27日下午4:54:24
*@description 描述:
*/
public class TCPFileCopyServer {
public static void main(String[] args) throws IOException {
//获取TCP服务端的对象
ServerSocket ss=new ServerSocket(9009);
Socket s=ss.accept();
//获取自带的字节输入流读取客户端发来的数据
InputStream is=s.getInputStream();
//接受文件名长度值
//int length=is.read();
byte length=(byte)is.read();
//新建字节数组
//byte[] bts=new byte[length];
byte[] bts=new byte[length+128];
//按照这个字节数组读取文件名内容
is.read(bts);//字节数组里存满了文件名内容
//创建文件字节输出流
//FileOutputStream fos=new FileOutputStream("D:\\a\\b\\"+new String(bts,0,length));//length为int
FileOutputStream fos=new FileOutputStream("D:\\a\\b\\"+new String(bts));
byte[] bs=new byte[1024*1024*10];
int len=-1;
while((len=is.read(bs))!=-1) {
//往外部文件写数据
fos.write(bs,0,len);
}
//通知客户端已经读取完毕
s.shutdownInput();
//关流
fos.close();
is.close();
}
}