资讯详情

java_web 快速入门之第九章 UDP连接&Map集合

一:网络通信协议(以)TCP/IP模型为例)

常用的网络通信协议:TCP/IP协议、IPX/SPX协议、NetBEUI协议等。

TCP/IP,即Transmission Control Protocol/Internet Protocol的简写 中译名为传输控制协议/因特网互联网协议Internet最基本的协议,Internet基于国际互联网。

二:IP地址和端口号(组合为网络套接字)

URL url = new URL("文件的地址"); 1.IP 地址:InetAddress(在Java中使用InetAddress类代表IP)

2.端口号 端口号是识别在计算机上运行的过程(程序) 不同的过程有不同的端口号 被规定为一个 16 位的整数 0~65535。

重点:TCP|IP传输层在模型中有两个重要协议:TCP协议和UDP协议

三:TCP协议详解

(1)使用TCP协议前必须建立TCP连接形成传输数据通道

(2) 在传输之前,点对点通信是可靠的。四次挥手

(3) TCP通信协议的两个应用程序:客户端和服务端。

(4) 大数据量的传输可以在连接中传输

(5) 传输完成后,需要释放已建立的连接,

TCP网络编程基于Socket实现服务端与客户端对话

四:UDP协议详解(无连接)

(1)将数据、源、目的包装成数据包,无需建立连接

(2) 每个数据报的大小限制在64K内部(以容器的形式发送)

(3) 无论对方是否准备好发送,接收方都不确认收到,因此不可靠

(4) 可广播发送

(5) 数据发送结束时无需释放资源,费用小,速度快

UDP没有服务器和客户端的说法,有发送方和接收方 DatagramSocket----比作发送方 比作接收方 DatagramPacket-----数据包装对象

a.类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。 b.UDP数据报告通过数据报套接字 DatagramSocket 系统不保证发送和接收 UDP数据报告必须能够安全地发送到目的地,也不能确定何时到达。 c.DatagramPacket 对象封装了UDP数据报包含在数据报中的发送端IP接收端的地址、端口号IP地址和端口号。 d.UDP协议中的每个数据报告都提供了完整的地址信息,因此无需建立发送方和接收方之间的连接。就像快递包裹一样。

五:UDP网络通信编程的基本概念

类DatagramSocket和DatagramPacktet[数据包|基于数据报】UDP协议网络程序 UDP数据报告通过数据报套接字DatagramSocket系统不保证发送和接受UDP数据报告必须能够安全地发送到目的地,也不能确定何时能够到达。 DatagramPacket对象封装了UDP数据报包含在数据报中的发送端IP地址和端口号以及接收端的IP地址和端口号。 UDP协议中的每个数据报告都提供了完整的地址信息,因此无需建立发送方和接收方之间的连接。

六:UDP网络编程的基本流程

  1. 核心两类/对象DatagramSocket与DatagramPacket

  2. 建立发送端和接收端

  3. 建立数据包

  4. 调用DatagramSocket发送和接收方法。

  5. 关闭DatagramSocket

注:发送端和接收端是两个独立的操作程序

UDP 不仅支持一对一传输,还支持一对多、多对多、多对一,即 UDP 提供单播、多播、广播的功能。

  • 单播

是指在计算机网络传输中封包一种传输方式,目的地址为单一目标。 【你对小月月喊小月月,那么只有小月月回头答应你。

  • 广播

是指在计算机网络中传输封包时,目的地址是网络中所有设备的一种传输方式。事实上,这里所说的所有设备也局限于一个范围,称为广播域。 255.255.255.255 【你在公司喊放假, 所有同事都会回应,大喊爽死。

  • 组播

也叫多播, 多点广播或群播。 它指的是将信息同时传输到一组目的地址。它使用策略是最有效的,因为每个网络链路只传输一次,只有在链路分叉时才会复制。

多播组通过 D 类 IP 地址和标准 UDP 指定端口号。D 类 IP 地址在 224.0.0.0 和 239.255.255.255 范围内(包括两者)。 224.0.0.0 被保留,不得使用。 【你在街上喊美女, 会有一群女人回头看你。

       发送的IP地址:238.222.111.0   接收方:   MulticastSocket ms=new MulticastSocket(4399);   /* 加入那个组加入那个组 */   ms.joinGroup(InetAddress.getByName("238.222.111.0"));   byte[] bs=new byte[100];   DatagramPacket dp=new DatagramPacket(bs, bs.length);   ms.receive(dp);   System.out.println(new String(bs).trim());   /* 离开小组 */   ms.leaveGroup(InetAddress.getByName("238.222.111.0"));   ms.close();

对于三种udp协议 1.发送方完全相同,单播指定一个ip 播是指定255.255.255.255这个ip                组播是指定D类ip(224-239)           2.接收方单播直接指定一个ip与端口               广播不能指定ip,只要端口               组播要使用MulticastSocket,               然后使用joinGroup加入该组

 

案例:UDP网络通信编程应用案例

  1. 编写一个接收端A,和一个发送端B
  2. 接收端A在9999端口等待接收数据(receiver)
  3.  发送端A向接收端B发送数据"hello,明天吃火锅~"
  4. 接收端B接收到发送端A发送的数据,回复"好的,明天见",再退出
  5. 发送端接收回复的数据,再退出

                          接收端A---------------UDPReceiverA.java  

package com.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
 * 接收端
 * 
 */
public class UDPReceiverA {
	public static void main(String[] args) throws Exception {
		// 1.创建一个DatagramSocket对象,准备在9999接收数据
		DatagramSocket socket = new DatagramSocket(9999);
		// 2.构建一个DatagramPacket对象,准备接收数据
		// 限制64K
		byte[] buf = new byte[1024];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);
		// 3.调用接收方法,将通过网络传输的DatagramPacket对象
		// 填充到packet对象
		// 注意事项:当有数据包发送到本机的9999端口时,就会接收到数据,如果没有数据包发送到本机的9999端口,就会堵塞等待。
		System.out.println("接收端A 等待接收...");
		socket.receive(packet);
		// 4.可以把packet进行拆包,取出数据,进行显示
		int length = packet.getLength();// 实际接收到的数据字节长度
		byte[] data = packet.getData();// 接收到数据
		String s = new String(data, 0, length);
		System.out.println("接收的内容为: " + s);
		// 关闭资源
		socket.close();
		System.out.println("A exit");
	}
}

         发送端B-------------------------------------------UDPSenderB.java

package com.test;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 发送端===>也可以接收数据
 *
 */
public class UDPSenderB {
	public static void main(String[] args) throws Exception {

		// 创建 DatagramSocket对象,准备在9998端口接收数据
		DatagramSocket socket = new DatagramSocket(9998);

		// 将需要发送的数据,封装到DatagramPacket对象
		byte[] data = "hello 明天吃火锅".getBytes();
		DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), 9999);

		// 发送数据
		socket.send(packet);

		// 关闭资源
		socket.close();

		System.out.println("B exit");
	}
}

案例: UDP传输协议演示

----------------------------------------------发送方-------------------------------------------------------------------------

​
package com.zking.test2;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * UDP传输协议
 * 
 * 
 * 
 * 1.一句话发送和接收 端口号9999
 * 
 * 发送方
 * 
 * @author Administrator
 *
 */
public class Sender {
	public static void main(String[] args) throws Exception {
		// 1.通过DatagramSocket是一个发送方,同时也可以比作成一个接收方
		DatagramSocket ds = new DatagramSocket(7979);
		System.out.println("发送方已开启");
		// 准备数据
		String str = "李太白今晚约会";
		// 进行打包
		DatagramPacket dp = null;
		// 已经打包成功
		// buf: 字节数组 数据包封装字节数组
		// length 字节数组的长度
		// address 发送方的IP地址
		// port 端口号
		dp = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 9999);
		// 发送
		ds.send(dp);
		System.out.println("发送完毕");
		
		//接收数据
		byte[] buf = new byte[1024];
		dp = new DatagramPacket(buf, buf.length);
		ds.receive(dp);//接收
		int length = dp.getLength();
		byte[] data = dp.getData();
		System.out.println(new String(data,0,length));
		
		ds.close();

	}
}

​

 

------------------------------------------接收方-----------------------------------------------------------------------------

package com.zking.test2;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 接收方-------也是发送方法
 * 
 * @author Administrator
 *
 */
public class Revicer {

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

		// 1.通过DatagramSocket是一个接收方,同时也可以比作成一个发送方
		DatagramSocket ds = new DatagramSocket(9999);// 该端口号来源与发送方
		System.out.println("接收方已开启成功......");
		// 2.准备一个数据包(DatagramPacket)
		DatagramPacket dp = null;// 定义好
		byte[] buf = new byte[1024];
		dp = new DatagramPacket(buf, buf.length);
		// 调用接收的方法将接收的数据进行封包。
		ds.receive(dp);
		// System.out.println(new String(buf).trim());
		// 获取数据的实际大小的长度
		int length = dp.getLength();
		// 获取打包的实际数据
		byte[] data = dp.getData();
		System.out.println(new String(data, 0, length));
		
		
		
		//接收方如果要回复信息
		String str = "好的带上装备今晚是个好日子";
		dp = new DatagramPacket(str.getBytes(), 
				str.getBytes().length, 
				InetAddress.getByName("127.0.0.1"), 7979);
		
		ds.send(dp);
		
		// 关闭
		ds.close();

	}

}

案例:群聊客户端与服务端

--------------------------------------------------服务器端---------------------------------------------------------------

package com.zking.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

/**
 * 服务器端
 * 
 * @author Administrator
 *
 */
public class MyServerChat {
	public static void main(String[] args) throws Exception {
		// 开启服务器
		ServerSocket ss = new ServerSocket(9797);
		System.out.println("服务器已开启成功");

		// 调用方法无线接收客户端 (群聊---多个客户端)

		// Vector
		Vector<Socket> vc = new Vector<Socket>();
		// 无线接收客户端
		while (true) {
			// 连一个
			Socket sk = ss.accept();
			// 加一个
			vc.add(sk);
			// 转一个
			new Thread(new MyServerThreadChat(vc, sk)).start();
		}
	}
}

class MyServerThreadChat implements Runnable {
	private Vector<Socket> vc;
	private Socket sk;

	public MyServerThreadChat(Vector<Socket> vc, Socket sk) {
		this.vc = vc;
		this.sk = sk;
	}

	@Override
	public void run() {
		while (true) {
			// 通过当前传递过来的连接服务器的客户端---sk 获取网络流读取内容
			try {
				InputStream is = sk.getInputStream();
				InputStreamReader isr = new InputStreamReader(is);
				BufferedReader br = new BufferedReader(isr);
				String readLine = br.readLine();
				System.out.println(readLine);
				if("bye".equals(readLine)) {
					vc.remove(sk);
				}
				// 当前的内容转发给其它客户端--不包括自己
				for (Socket socket : vc) {
					if (socket != null) {// 排除空对象
						if (socket != sk) {
							// 将内容写入其它所有客户端
							OutputStream os = socket.getOutputStream();
							OutputStreamWriter osw = new OutputStreamWriter(os);
							BufferedWriter bw = new BufferedWriter(osw);
							bw.write(readLine);
							bw.newLine();
							bw.flush();
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

-------------------------------------------------------------客户端-----------------------------------------------------------

package com.zking.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 客户端
 * @author Administrator
 *
 */
public class MyClientChat {
	public static void main(String[] args) throws Exception{
		//开启客户端
		Socket sk = new Socket("127.0.0.1", 9797);
		System.out.println("OK了........");
		//发送-------输出
		new Thread(new MyClientThreadChat1(sk)).start();
		
		//接收-----输入
		new Thread(new MyClientThreadChat1(sk)).start();
	}
}

//线程发送
class MyClientThreadChat1 implements Runnable{
	private Socket sk = null;
	public MyClientThreadChat1(Socket sk) {
		this.sk = sk;
	}
	@Override
	public void run() {
		while(true) {
			try {
				OutputStream os = sk.getOutputStream();
				BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
				Scanner sc = new Scanner(System.in);
				System.out.println("发送内容: ");
				String next = sc.next();
				bw.write(next);
				bw.newLine();
				bw.flush();
				if("bye".equalsIgnoreCase(next)) {
					break;
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}


//无线接收
class MyClientThreadChat2 implements Runnable{
	private Socket sk = null;
	public MyClientThreadChat2(Socket sk) {
		this.sk = sk;
	}
	@Override
	public void run() {
		while(true) {
			try {
				InputStream is = sk.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(is));
				
				String readLine = br.readLine();
				System.out.println("   "+readLine);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}





七:Map集合

  1. Map集合是一个双列集合,一个元素包含了两个值(key和value);
  2. Map集合中的元素,key和value可以相同,也可以不同;
  3. Map集合中的元素,key是不允许重复的,value是可以重复的;
  4. Map中的元素,key和value是一一对应的;

 

  • HashMap

  • java.util.HashMap implements Map<k,v>接口;

特点:

  1. HashMap集合底层是哈希表,查询速度特别快,多线程的集合,线程不安全
  2. HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致,并且可以存储null键和null值;

  • LinkedHashMap

  • java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合

特点:

     1.LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序);      2. LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是有序的;  

  • HashTable

  • java.util.LinkedHashtable<K,V>集合 implements Map<K,V>接口

特点:底层也是一个哈希表,是线程安全的集合,是单线程的集合,速度慢,不能存储null值null键;

 

  • 方法集合

  • put(K key , V value) : 把指定的键与指定的值添加到Map集合中;

  1. 存储键值对的时候,k不重复的情况下,返回的v是null;
  2. 存储键值对的时候,k重复的情况下,会使用新的value替换重复的k对应的value,然后返回被替换的value;
  • remove(Object key) : 把指定的键所对应的键值对元素,在Map集合中删除,返回被删除元素的值;

  1. 如果key存在,v返回被删除的值;
  2. 如果Key不存在,v返回null;
  • get(Object key) : 根据指定的键,在Map中获取对应的值;

  1. 如果key存在,v返回被对应的值;
  2. 如果Key不存在,v返回null;
  • containsKey(Obejct key) : 判断集合中是否包含指定的key;

  1. 包含返回true;
  2. 不包含返回false;

基本使用:

  •  

Map map = new HashMap();		
map.put("杨过", "小龙女");
map.put("李太白", "王昭君");
map.put("李世民", "武则天");
System.out.println(map.size());//3
map.clear();
System.out.println(map.size());//0
boolean containsKey = map.containsKey("李太白");
System.out.println(containsKey);
boolean containsValue = map.containsValue("小龙女");
System.out.println(containsValue);
Object object = map.get("李太白");
System.out.println(object);
		
boolean empty = map.isEmpty();
System.out.println(empty);
Object remove = map.remove("李太白");
System.out.println(remove);
System.out.println(map.size());

集合遍历:

Collection values = map.values();//获取所有的值
	for (Object object : values) {
			System.out.println(object);
		}

  •   键找值

  1. 使用Map集合中的keySet(),把Map集合中所有的key取出来存储到一个set集合中;
  2. 遍历set集合,获取Map中的每一个key;
  3. 通过Map集合的get()方法,获取key对应的value;
Set keySet = map.keySet();
		for (Object object : keySet) {
		System.out.println(object);
		}
需求:定义一个Map集合  一次行进行遍历输出
		Map map = new HashMap();
		map.put("ZG", "中国");
		map.put("MG", "美国");
		map.put("RB", "日本");
		map.put("YG", "英国");
		map.put("XBY", "西班牙");
		
		//得到所有的键
		Set keySet = map.keySet();
		for (Object object : keySet) {
			//根据获取的键再获取对应的值
			Object object2 = map.get(object);
			System.out.println(object+"----"+object2);
	}

     

         entrySet  对象,将集合中的每一个键值对进行封装  得到一个entry对象 ,因此键和值作为了        Entry对象的属性   可以通过entrySet+迭代器进行遍历

  1. 使用Map集合中的keySet(),把Map集合中所有的key取出来存储到一个set集合中;
  2. 遍历set集合,获取Map中的每一个key;
  3. 通过Map集合的get()方法,获取key对应的value;

     


		//1.调用entrySet方法将集合中的键值对封装每一个Entry对象存储到Set集合中
		Set entrySet = map.entrySet();
	//2.通过所谓的迭代器
		Iterator iterator = entrySet.iterator();
		//3.遍历迭代器
		while(iterator.hasNext()) {//如果迭代器中存在下一条数据
			//直接获取
		System.out.println(iterator.next());
		Entry<String, String> entry = (Entry<String, String>) iterator.next();
			System.out.println(entry.getKey()+ "\t"+entry.getValue());//获取所有的键和值
			
		}
		

案例:有10间监狱   每间监狱中有10个犯人             每间监狱的房间名称:   1号   2号  .....

                要求:使用Map集合完成以上需求定义

Map<String,List<FanRen>> map2 = new HashMap<String,List<FanRen>>();
		
		//模拟数据
		for (int i = 1; i <= 10; i++) {//10间房
			List<FanRen> list = new ArrayList<FanRen>();
			//每间房间  有10个犯人
			for (int j = 1; j <= 10; j++) {
				FanRen fr = new FanRen(j+1, "张三"+j, "男");
				//每创建一个犯人  加入List集合
				list.add(fr);
			}
			//将每间房加入map集合
			map2.put(i+"号房间", list);
		}
		
		System.out.println(map2.size());
		
		//遍历显示
		Set<Entry<String, List<FanRen>>> entrySet = map2.entrySet();
		
		Iterator<Entry<String, List<FanRen>>> iterator = entrySet.iterator();
		
		while(iterator.hasNext()) {
			Entry<String, List<FanRen>> next = iterator.next();
			System.out.println("监狱房间号: "+next.getKey());
			List<FanRen> value = next.getValue();
			for (FanRen fanRen : value) {
				System.out.println("\t"+fanRen);
			}
		}

Map<GoodsType,List<Goods>> map3 = new HashMap<GoodsType,List<Goods>>();)

案例:文件发送接收

------------------------------------------发送方---------------------------------------------------------------------------

package com.zking.test3;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 发送方
 * @author Administrator
 *
 */
public class Sender {
	public static void main(String[] args) throws Exception{
		//三边原则:边读  边打包 边发送
		
		//定义发送方
		DatagramSocket ds = new DatagramSocket();
		//准备数据报容器
		DatagramPacket dp = null;
		
		
		//1.指定图片文件
		File file = new File("D:\\a.jpg");
		//通过流进行读取
		FileInputStream fis = new FileInputStream(file);
		//转缓冲流
		BufferedInputStream bis = new BufferedInputStream(fis);
		
		//读取文件每次读取一个字节数组
		byte[] bytes = new byte[10];
		int len = 0;//保存读取后的下表
//		边读
		int count = 10;
		while(-1!=(len = bis.read(bytes))) {
//			边打包
			dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 7979);
//			边发送
			ds.send(dp);
			Thread.sleep(100);
			count+=10;
			System.out.println(count);
		}
		//问题:接受方没有关闭-----手动再发送一个标记(如果接收方接到标记后,方可关闭)
		dp = new DatagramPacket("sb".getBytes(), "sb".getBytes().length,
				InetAddress.getByName("127.0.0.1"), 7979);
		
		ds.send(dp);
		
		
		
		
		
		
	}
}

------------------------------------------接收方----------------------------------------------------------------------------

package com.zking.test3;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * 接收方
 * @author Administrator
 *
 */
public class Revicer {

	public static void main(String[] args) throws Exception{
		// 边收   边拆  边写
		//接收方对象
		DatagramSocket ds = new DatagramSocket(7979);
		
		DatagramPacket dp = null;
		
		//定义保存的文件对象路径
		File file = new File("D:\\c.jpg");
		FileOutputStream fos = new FileOutputStream(file);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		//定义一个字节数组
		byte [] bytes = new byte[10];
		int count = 10;
		while(true) {
			//接收数据包
			dp = new DatagramPacket(bytes, bytes.length);
			//边收
			ds.receive(dp);
			
			if(new String(bytes).contains("sb")) {//bytes  sb  结束了
				System.out.println("全部接收完毕");
				break;
			}
			count+=10;
			System.out.println(count);
			bos.write(bytes);
		}
		
		
		
	}

}

标签: mg643183连接器mg642570连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台