JAVA-套接字

网络基本概念

七层模型:物理层 数据链路层 网络层 传输层 - UDP/TCP 会话层 应用层 表示层 — HTTP、FTP、POP3、SMTP …
IP地址:在网络中标记主机。
IPv4 — 四组数表示一个IP地址,每一组数的取值范围是0-255
IPv6 — 六组数表示一个IP地址
端口:计算机与外界交互的媒介 — 端口号 — 0~65535 — 0-1024
域名:各个网站提供的便于记忆的标记
DNS解析服务器:将域名和IP地址进行对应

UDP

基于流的。不建立连接,不可靠。传输速度相对比较快的。需要对数据进行封包,每个包不超过64K大小。 适用于对速度依赖性比较强但是对可靠性依赖性比较低的场景 — 视频聊天 — DatagramSocket DatagramPacket

通信过程

发送端:

  1. 创建套接字对象
  2. 准备数据包,将数据放入数据包中,并且绑定要发往的地址
  3. 发送数据包
  4. 关流

接收端:

  1. 创建套接字对象,并且绑定要接收的端口号
  2. 准备数据包
  3. 接收数据
  4. 关流
  5. 解析数据

案例:使用一个线程表示发送端,一个线程表示接收端—实现单人聊天功能

public class UDPChatDemo {

   public static void main(String[] args) {

   	new Thread(new Sender()).start();
   	new Thread(new Receiver()).start();

   }

}

// 发送端
class Sender implements Runnable {

   private DatagramSocket ds;
   private DatagramPacket dp;
   private Scanner s;

   {
   	try {
   		// 创建套接字对象
   		ds = new DatagramSocket();
   		s = new Scanner(System.in);
   	} catch (Exception e) {
   		e.printStackTrace();
   	}

   }

   @Override
   public void run() {

   	while (true) {

   		// 读取数据
   		byte[] bs = s.nextLine().getBytes();

   		// 准备数据包
   		dp = new DatagramPacket(bs, bs.length, new InetSocketAddress("255.255.255.255", 8090));

   		try {
   			// 发送数据
   			ds.send(dp);
   		} catch (IOException e) {
   			e.printStackTrace();
   		}

   	}

   }

}

// 接收端
class Receiver implements Runnable {

   private DatagramSocket ds;
   private DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);

   {

   	// 创建UDP对象并且绑定端口号
   	try {
   		ds = new DatagramSocket(8090);
   	} catch (SocketException e) {
   		e.printStackTrace();
   	}
   }

   @Override
   public void run() {

   	while (true) {

   		try {
   			// 接收数据
   			ds.receive(dp);

   			// 解析数据
   			System.out.println(dp.getAddress() + ":");
   			System.out.println(new String(dp.getData(), 0, dp.getLength()));

   		} catch (IOException e) {
   			e.printStackTrace();
   		}

   	}

   }
}

TCP

基于流的。建立连接,经历三次握手,可靠。但是传输速率相对较慢。理论上不限制传输的数据的大小。适用于对可靠性的依赖性更高对速度依赖性较低的场景 — 文件传输
在这里插入图片描述
注意:receive/connect/accept/write/read都会产生阻塞。
BIO - Blocking IO - 同步式阻塞式IO
NIO - New IO - NonBlocking IO - 同步式非阻塞式IO - JDK1.4
AIO - Asynchronous IO - 异步式非阻塞式IO - JDK1.8

通信过程

客户端 - Socket

  1. 创建客户端的套接字对象
  2. 发起连接,绑定连接地址
  3. 获取自带的输出流,写出数据,禁用输出流
  4. 如果服务器端有打回的数据,则需要获取输入流读取数据,禁用输入流
  5. 关流

服务器端 - ServerSocket

  1. 创建服务器端的套接字对象,并且绑定监听的端口号
  2. 接受连接,获取到一个Socket对象
  3. 获取输入流,读取消息,禁用输入流
  4. 如果需要向客户端打回消息,则需要获取输出流写出数据,禁用输出流
  5. 关流

案例:上传文件 - 在客户端读取文件并将读取的内容传到服务器端;在服务器端接收数据然后将接收的数据在写到对应的文件上

Tips:如果文件名的字节个数超过了一个字节所能表示的范围,那么这个时候可以用2个字节传输所表示文件名的字节个数
byte n = (byte)(len / 256); // 确定文件名中有几个完整的字节
byte left = (byte)(len % 256 - 128); // 去掉完整字节之后的剩余的可以传输的字节个数
读取的时候通过int len = n * 256 + left + 128; 从而表示完整的全部文件名占用的字节个数

public class FileClient {

	public static void main(String[] args) throws Exception {

		// 创建一个客户端的套接字对象并且发起连接
		Socket s = new Socket();
		s.connect(new InetSocketAddress("localhost", 8090));

		// 获取输出流
		OutputStream out = s.getOutputStream();

		// 创建File对象指向要写出文件
		File file = new File("E:\\JAVASE.xmind");

		// 获取文件的名字及类型
		byte[] name = file.getName().getBytes();
		
		// 写出文件名的长度
		byte n=(byte)(name.length/256);
		byte left=(byte)(name.length%256-128);
		out.write(n*256+left+128);
		
		// 写出文件名
		out.write(name);

		// 读取文件内容并将内容写出
		FileInputStream fin = new FileInputStream(file);
		byte[] bs = new byte[1024];
		int len = -1;
		while ((len = fin.read(bs)) != -1)
			out.write(bs, 0, len);

		// 关流
		s.shutdownOutput();
		fin.close();
		s.close();

	}

}


public class FileServer {

	public static void main(String[] args) throws Exception {

		// 创建服务器端的套接字对象并接受连接
		ServerSocket ss = new ServerSocket(8090);
		Socket s = ss.accept();

		// 获取输入流
		InputStream in = s.getInputStream();

		// 读取文件名的长度
		int len = in.read();

		// 读取文件名
		byte[] name = new byte[len];
		in.read(name);

		// 读取文件内容,并将读取的数据写出
		FileOutputStream fout = new FileOutputStream("D:\\" + new String(name));
		byte[] bs = new byte[1024];
		int i = -1;
		while ((i = in.read(bs)) != -1)
			fout.write(bs, 0, i);

		// 关流
		s.shutdownInput();
		fout.close();
		ss.close();

	}

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值