网络编程之UDP编程

  • 网络编程之UDP编程
UDP协议是一种不可靠的网络协议,它在通信的2端各建立一个Socket,但是这个Socket之间并没有虚拟链路,这2个Socket只是发送和接受数据的对象,Java提供了DatagramSocket对象作为基于UDP协议的Socket,使用DatagramPacket代表DatagramSocket发送和接受数据报。值得注意的是:UDP编程必须先由客户端发出信息。一个客户端就是一封信,Socket相当于美国式邮筒(信件的收发都在一个邮筒中)。端口与协议相关,所以TCP的3000端口与UDP的3000端口不是同一个端口。关于这种方式了解下就好了,实际编码中反正我是从来没有用到过。


以下代码实现了使用DatagramSocket发送和接受数据:

import java.net.*;
import java.io.*;

public class UdpServer
{
	public static final int PORT = 30000;
	// 定义每个数据报的最大大小为4K
	private static final int DATA_LEN = 4096;
	// 定义接收网络数据的字节数组
	byte[] inBuff = new byte[DATA_LEN];
	// 以指定字节数组创建准备接受数据的DatagramPacket对象
	private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
	// 定义一个用于发送的DatagramPacket对象
	private DatagramPacket outPacket;
	// 定义一个字符串数组,服务器发送该数组的的元素
	String[] books = new String[] { "LinkinPark", "NightWish", "林肯公园", "夜愿。。。" };

	public void init() throws IOException
	{
		// 创建DatagramSocket对象
		DatagramSocket socket = null;
		try
		{
			socket = new DatagramSocket(PORT);
			// 采用循环接受数据
			for (int i = 0; i < 1000; i++)
			{
				// 读取Socket中的数据,读到的数据放入inPacket封装的数组里。
				socket.receive(inPacket);
				// 判断inPacket.getData()和inBuff是否是同一个数组
				System.out.println(inBuff == inPacket.getData());
				// 将接收到的内容转成字符串后输出
				System.out.println(new String(inBuff, 0, inPacket.getLength()));
				// 从字符串数组中取出一个元素作为发送的数据
				byte[] sendData = books[i % 4].getBytes();
				// 以指定字节数组作为发送数据、以刚接受到的DatagramPacket的
				// 源SocketAddress作为目标SocketAddress创建DatagramPacket。
				outPacket = new DatagramPacket(sendData, sendData.length, inPacket.getSocketAddress());
				// 发送数据
				socket.send(outPacket);
			}
		}
		finally
		{
			if (socket != null)
			{
				socket.close();
			}
		}
	}

	public static void main(String[] args) throws IOException
	{
		new UdpServer().init();
	}
}

import java.net.*;
import java.io.*;
import java.util.*;

public class UdpClient
{
	// 定义发送数据报的目的地
	public static final int DEST_PORT = 30000;
	public static final String DEST_IP = "127.0.0.1";
	// 定义每个数据报的最大大小为4K
	private static final int DATA_LEN = 4096;
	// 定义接收网络数据的字节数组
	byte[] inBuff = new byte[DATA_LEN];
	// 以指定字节数组创建准备接受数据的DatagramPacket对象
	private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
	// 定义一个用于发送的DatagramPacket对象
	private DatagramPacket outPacket = null;

	public void init() throws IOException
	{
		// 创建一个客户端DatagramSocket,使用随机端口
		DatagramSocket socket = null;
		try
		{
			socket = new DatagramSocket();
			// 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
			outPacket = new DatagramPacket(new byte[0], 0, InetAddress.getByName(DEST_IP), DEST_PORT);
			// 创建键盘输入流
			Scanner scan = new Scanner(System.in);
			// 不断读取键盘输入
			while (scan.hasNextLine())
			{
				// 将键盘输入的一行字符串转换字节数组
				byte[] buff = scan.nextLine().getBytes();
				// 设置发送用的DatagramPacket里的字节数据
				outPacket.setData(buff);
				// 发送数据报
				socket.send(outPacket);
				// 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组里。
				socket.receive(inPacket);
				System.out.println(new String(inBuff, 0, inPacket.getLength()));
			}
		}
		finally
		{
			if (socket != null)
			{
				socket.close();
			}
		}
	}

	public static void main(String[] args) throws IOException
	{
		new UdpClient().init();
	}
}


  • 最后介绍下代理服务器:
什么是代理服务器?
代理服务器的功能就是代理网络用户去获得网络信息。代理服务器就是介于浏览器和web服务器之间的一台服务器,有了这个代理服务器之后,浏览器不是直接到web服务器去获得页面信息而是向刚才那台向刚才我们加的那一台代理服务器去发送请求,由代理服务器去取的网页数据然后发送给网络服务器。其中呢关于网络服务器还有一个最大的好处就是缓存,总结一下代理服务器有如下功能:
1,突破自身IP限制,对外隐藏自身的IP地址,那么这样子就会安全一些
2,提高访问速度,因为他具有强大的缓存功能(cache)


相关贴出2篇代码,了解下就好了:
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * 
 * @version 1L
 * @author LinkinPark
 * @since 2015-2-11
 * @motto 梦似烟花心似水,同学少年不言情
 * @desc ^以URLConnection为例介绍如何在URLConnection中使用代理服务器
 */
public class ProxyTest
{
	// 下面是代理服务器的地址和端口,
	// 换成实际有效的代理服务器的地址和端口
	final String PROXY_ADDR = "129.82.12.188";
	final int PROXY_PORT = 3124;
	// 定义需要访问的网站地址
	String urlStr = "http://www.crazyit.org";

	public void init() 
		throws IOException , MalformedURLException
	{
		URL url = new URL(urlStr);
		// 创建一个代理服务器对象
		Proxy proxy = new Proxy(Proxy.Type.HTTP 
			, new InetSocketAddress(PROXY_ADDR , PROXY_PORT));
		// 使用指定的代理服务器打开连接
		URLConnection conn = url.openConnection(proxy);
		// 设置超时时长。
		conn.setConnectTimeout(5000);
		try(
			// 通过代理服务器读取数据的Scanner
			Scanner scan = new Scanner(conn.getInputStream(), "utf-8");
			PrintStream ps = new PrintStream("index.htm"))
		{
			while (scan.hasNextLine())
			{
				String line = scan.nextLine();
				// 在控制台输出网页资源内容
				System.out.println(line);
				// 将网页资源内容输出到指定输出流
				ps.println(line);
			}
		}
	}

	public static void main(String[] args) throws IOException, MalformedURLException
	{
		new ProxyTest().init();
	}
}

import java.io.*;
import java.net.*;
import java.util.*;


/**
 *
 * @version 1L
 * @author  LinkinPark 
 * @since   2015-2-11
 * @motto   梦似烟花心似水,同学少年不言情
 * @desc    ^通过改变系统属性来改变默认的代理服务器
 */
public class ProxySelectorTest
{
	// 下面是代理服务器的地址和端口,
	// 随便一个代理服务器的地址和端口
	final String PROXY_ADDR = "139.82.12.188";
	final int PROXY_PORT = 3124;
	// 定义需要访问的网站地址
	String urlStr = "http://www.crazyit.org";

	public void init() 
		throws IOException , MalformedURLException
	{
		// 注册默认的代理选择器
		ProxySelector.setDefault(new ProxySelector()
		{
			@Override
			public void connectFailed(URI uri
				, SocketAddress sa, IOException ioe)
			{
				System.out.println("无法连接到指定代理服务器!");
			}
			// 根据"业务需要"返回特定的对应的代理服务器
			@Override
			public List<Proxy> select(URI uri)
			{
				// 本程序总是返回某个固定的代理服务器。
				List<Proxy> result = new ArrayList<>();
				result.add(new Proxy(Proxy.Type.HTTP 
					, new InetSocketAddress(PROXY_ADDR , PROXY_PORT)));
				return result;
			}
		});
		URL url = new URL(urlStr);
		// 没有指定代理服务器、直接打开连接
		URLConnection conn = url.openConnection();   //①
		// 设置超时时长。
		conn.setConnectTimeout(3000);
		try(
			// 通过代理服务器读取数据的Scanner
			Scanner scan = new Scanner(conn.getInputStream());
			PrintStream ps = new PrintStream("index.htm"))
		{
			while (scan.hasNextLine())
			{
				String line = scan.nextLine();
				// 在控制台输出网页资源内容
				System.out.println(line);
				// 将网页资源内容输出到指定输出流
				ps.println(line);
			}
		}
	}

	public static void main(String[] args) throws IOException, MalformedURLException
	{
		new ProxySelectorTest().init();
	}
}


  • 在这里顺便介绍一下URL
URL:统一资源定位器。它是指向互联网资源的指针。资源可以是简单的文件和目录,也可以是对更加复杂的对象的引用。
值得注意的是,URL一般由协议名,主机,端口和资源组成。比如:http://localhost:8080/tzTaskManage/Login.jsp


最后贴出一段普通的下载程序结束网络编程。前面的TCP的常用类中也有一篇是下载的代码,那里的代码稍微复杂一点,那里实现了多线程下载的功能,当然还可以更加复杂一点,就是在那个的基础上再提供一个配置文件,用来记录每一个线程下载到了什么地方了,下载继续的时候就可以从那里开始继续,这也就是断点下载。以下代码是普通下载的核心:

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class DownLoad
{
	public static void main(String[] args) throws Exception
	{
		String str = "http://localhost/project_document.zip";
		URL url = new URL(str);//上句指定下载的地址和文件
		URLConnection urlConn = url.openConnection();
		urlConn.connect();//获得连接然后在获得输入流
		InputStream is = urlConn.getInputStream();
		FileOutputStream fos = new FileOutputStream("/home/sd0807/down.zip");
		byte[] buf = new byte[4096]; //上句指定下载的地址和下载后的名称
		int length = 0;
		while ((length = is.read(buf)) != -1)
		{
			fos.write(buf, 0, length);
		}
		fos.close();
		is.close();
	}
}


原文地址:https://www.cnblogs.com/LinkinPark/p/5233092.html