`
xpenxpen
  • 浏览: 731684 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JDK发送接收TCP/UDP数据

阅读更多
本文的理论和代码摘录于《疯狂Java讲义》http://book.51cto.com/art/201203/322540.htm,测试部分的截图是本人增加的。

1.UDP协议和TCP协议简单对比如下。
TCP协议:可靠,传输大小无限制,但是需要连接建立时间,差错控制开销大。
UDP协议:不可靠,差错控制开销较小,传输大小限制在64KB以下,不需要建立连接。

2.使用DatagramSocket发送接收UDP数据

2.1 理论
JDK使用DatagramSocket代表UDP协议的Socket,DatagramSocket类似于码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报。
而DatagramPacket代表数据报,类似于集装箱。码头的作用就是负责发送、接收集装箱,而DatagramSocket的作用则是发送、接收DatagramPacket。

使用DatagramSocket发送数据报时,DatagramSocket并不知道将该数据报发送到哪里,而是由DatagramPacket自身决定数据报的目的地。就像码头并不知道每个集装箱的目的地,码头只是将这些集装箱发送出去,而集装箱本身包含了该集装箱的目的地。

发送数据是通过DatagramSocket的send()方法实现的,send()方法根据数据报的目的地址来寻径以传送数据报。

在接收数据之前,应该生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用DatagramSocket的receive()方法等待数据报的到来,receive()将一直等待(该方法会阻塞调用该方法的线程),直到收到一个数据报为止。

当接收到一个DatagramPacket对象后,如果想向该数据报的发送者"反馈"一些信息,但由于UDP协议是面向非连接的,所以接收者并不知道每个数据报由谁发送过来,但程序可以调用DatagramPacket的如下3个方法来获取发送者的IP地址和端口。
InetAddress getAddress()
int getPort()
SocketAddress getSocketAddress()

2.2 编码
下面程序使用DatagramSocket实现了Server/Client结构的网络通信。本程序的服务器端使用循环1000次来读取DatagramSocket中的数据报,每当读取到内容之后便向该数据报的发送者送回一条信息。服务器端程序代码如下。
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UdpServer {
	public static final int PORT = 30000;
	// 定义每个数据报的最大大小为4KB
	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[] { "疯狂Java讲义", "轻量级Java EE企业应用实战",
			"疯狂Android讲义", "疯狂Ajax讲义" };

	public void init() throws IOException {
		// 创建DatagramSocket对象
		DatagramSocket socket = new DatagramSocket(PORT);

		// 采用循环接收数据
		for (int i = 0; i < 1000; i++) {
			// 读取Socket中的数据,读到的数据放入inPacket封装的数组里
			socket.receive(inPacket);
			// 判断inPacket.getData()和inBuff是否是同一个数组
			//getData()的API设计显得有些多余--直接访问传给 DatagramPacket构造器的字节数组实参即可,无须调用该方法
			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);
		}
	}

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


客户端采用循环不断地读取用户键盘输入,每当读取到用户输入的内容后就将该内容封装成DatagramPacket数据报,再将该数据报发送出去;接着把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该DatagramPacket所封装的字节数组中)。客户端程序代码如下。
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class UdpClient {
	// 定义发送数据报的目的地
	public static final int DEST_PORT = 30000;
	public static final String DEST_IP = "127.0.0.1";
	// 定义每个数据报的最大大小为4KB
	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 = 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()));
		}
	}

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


2.3 测试
下面我们测试一下,打开UdpServer,然后打开2个UdpClient。随便哪个Client都可以发消息给Server,同时会Server的回复。
Process Explorer监控一下端口可以发现,Server开启了30000端口,而Client则开启了随机端口,这次Client1是49509,Client2是52535。
服务器和Client1、Client2都是没有连接的。



3.使用Socket发送接收TCP数据
对比之下,如果是TCP的话,就是一般的Socket和ServerSocket互通。
服务端
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server
{
	public static void main(String[] args) 
		throws IOException
	{
		// 创建一个ServerSocket,用于监听客户端Socket的连接请求
		ServerSocket ss = new ServerSocket(30000);
		// 采用循环不断接受来自客户端的请求
		while (true) {
			// 每当接受到客户端Socket的请求,服务器端也对应产生一个Socket,并开启一个新线程负责和客户端通信
			final Socket s = ss.accept();
			new Thread(new Runnable(){

				@Override
				public void run() {
					// 将Socket对应的输出流包装成PrintStream
					PrintStream ps=null;
					try {
						ps = new PrintStream(s.getOutputStream());
						int i=9;
						//此处死循环是为了观察端口,不然下面的ps一关闭,就看不到端口情况了
						while (i==9) {
							ps.println("您好,您收到了服务器的新年祝福!");
						}
						ps.close();
						s.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					
				}
				
			}
			)
			.start();
		}
	}
}


客户端
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;

public class Client
{
	public static void main(String[] args) 
		throws Exception
	{
		Socket socket = new Socket("127.0.0.1" , 30000);
		BufferedReader br = new BufferedReader(
		new InputStreamReader(socket.getInputStream()));
		int i=9;
		while (i==9) {
			String line = br.readLine();
			System.out.println("来自服务器的数据:" + line);
		}
		br.close();
		socket.close();
	}
}


我们也可以做个试验,开启1个Server,2个Client。
从图中可以发现,Server开启了30000端口,并且和Client的53170和53171建立了连接。同时Server的30000端口还在监听准备接受新的Client的到来。




我们做另一个测试,同时开启UdpServer,UdpClient,并同时开启(TCP)Server,Client,发现他们不会冲突,都正常工作呢。


由此可以得到另外一个结论:TCP和UDP端口是独立的,他们之间没有关系。TCP可以有65536个端口,UDP同样也有65536个端口可用。这样一台计算机上总共就有131072个端口可用。
  • 大小: 72.1 KB
  • 大小: 59.1 KB
  • 大小: 81.2 KB
  • 大小: 4.6 KB
  • 大小: 3.8 KB
分享到:
评论

相关推荐

    Java习题十一.docx

    DatagramSocket 是用于发送和接收数据报的类,而 DatagramPacket 是用于封装要发送的数据的类。 三、Socket 编程 Socket 编程是网络编程的基础,Java 中提供了 Socket 和 ServerSocket 两个类来实现 socket 编程。...

    基于UDP的聊天和TCPIP的文件传输的设计与实现

    - **技术实现**:使用TCP Socket建立连接,将文件数据分成多个数据包发送,并等待确认。 - **进度显示**:提供文件传输进度的显示功能,让用户了解文件传输的状态。 ##### 3.6 文件接收过程 - **功能说明**:负责...

    使用Java JDK中Java[1].net包控制UDP协议

    这种特性使得UDP在发送数据时的延迟极低,非常适合实时数据传输。 2. **资源消耗与处理速度**:由于UDP不需要维护连接状态,如收发状态等,因此它对系统资源的消耗较小,处理速度较快。这一点对于音频、视频等...

    基于TCP的 Socket即时通信软件的设计与实现

    TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,而UDP(User Datagram Protocol)则是无连接的、不可靠的传输协议。两者各有特点,适用于不同的应用场景。 在TCP的...

    UDP局域网聊天传送文件

    在Java中,`java.net.DatagramSocket` 类用于创建UDP套接字,它允许发送和接收数据报(datagrams)。`DatagramPacket` 类则用来封装要发送的数据和接收的数据报。 3. 局域网通信: 局域网内的通信通常基于IP地址...

    计算机网络应用程序设计教案.docx

    学生需要理解Socket通信的基本模式,包括建立连接、发送和接收数据的步骤,并通过示例进行实践。 第七讲介绍了UDP协议和数据报套接字。UDP(用户数据报协议)是无连接的,相比TCP提供更低延迟但不保证数据可靠性。...

    java网络编程之UDP协议通信

    - **发送数据**:客户端通过`send(DatagramPacket packet)`方法将数据包发送到服务器。 - **接收数据**:服务器端使用`receive(DatagramPacket packet)`方法接收数据包,此方法会阻塞直到接收到一个包。 - **关闭...

    计算机网络课程设计报告-UDP编程.docx

    发送方创建DatagramSocket发送数据,接收方则创建DatagramSocket监听特定端口并接收数据。 ### 四、调试分析 在开发过程中可能遇到的问题包括:界面响应不灵敏、缺少必要的包导入、输入数据格式错误等。解决这些...

    基于Java的系统网络编程.pdf

    * TCP协议在正式通信前必须与对方建立起可靠的连接,在数据传输前,信息发送方和信息接收方之间先要进行信息交换的测试 * UDP(User Datagram Protocol,用户数据报协议)是一种面向非连接的协议 * UDP协议在正式...

    中南大学计算机网络实验源代码

    例如,服务器端可能包含监听新连接、接受客户端请求、处理数据并响应的循环,而客户端则负责发起连接、发送数据并接收回应。代码中可能还包含错误处理机制,如超时重试、异常捕获等,这些都是实际网络编程中必不可少...

    java课程设计 自己精心做的

    每个层次都有其特定的任务,如网络层的IP协议负责分组路由,传输层的TCP和UDP协议提供数据传输服务,而应用层的SMTP协议则用于邮件的发送。 通过这个课程设计,学生不仅会接触到电子邮件的底层工作原理,还会学习到...

    网络编程期中考试-参考答案.pdf

    网络编程是指使用编程语言开发的程序能够发送和接收数据包,实现信息的交互和数据传输。它涉及到多层协议的协同工作,最终通过物理线路进行信息的传输。网络编程主要可以分为网络层、传输层、会话层、表示层和应用层...

    使用UDP实现Echo服务.rar_Echo Echo_java udp

    Echo服务是一种基础的网络通信协议,它通过发送数据报文并接收相同的数据报文来测试网络连接的状态。在本教程中,我们将详细讨论如何使用Java编程语言实现一个基于UDP(User Datagram Protocol)的Echo服务。 UDP是...

    第9章 网络编程-课后习题1

    UDP不建立连接,直接发送数据报包,因此在数据传输时不需要预先建立逻辑连接。 3. **JDK提供的网络编程类**: - `DatagramSocket`类:用于发送和接收`DatagramPacket`,这是UDP协议的基础。 - `ServerSocket`和`...

    udp协议播放器.docx

    总的来说,UDP协议播放器利用了UDP的高效性和多播技术的广播特性,实现了向多个接收者同时发送数据的能力,尤其适用于实时性要求高、数据丢失容忍度大的应用场景。Java的`java.net`包提供了对多播套接字的全面支持,...

    疯狂android资料:第十三章android的网络应用.doc

    Android系统完全兼容JDK的网络通信API,包括TCP和UDP协议,以及HTTP通信。下面我们将深入探讨Android中基于TCP协议的网络通信。 **TCP协议基础** TCP(Transmission Control Protocol)是一种面向连接的、可靠的...

    JDK_API_1.6.zip

    2. 网络编程:java.net包提供了Socket、ServerSocket、URL等类,支持TCP/IP和UDP通信,实现网络应用。 3. 数据库操作:JDBC(Java Database Connectivity)接口允许Java程序与各种数据库进行交互,如建立连接、执行...

    基于UDP的JAVA网络编程

    - **数据发送**:发送端通过`DatagramSocket`创建`DatagramPacket`对象,并调用`send()`方法发送数据。 ```java public void sendData(String msg) { byte[] b = new byte[1024]; DatagramPacket packet; try...

    清华学子笔记录-java网络编程

    - **基于URL的网络编程**:主要针对Web资源访问,如HTTP请求的发送与接收。 - **基于TCP的C/S网络编程**:包括单客户端与多客户端场景下的通信实现。 - **基于UDP的C/S网络编程**:适用于不需要可靠传输的场合,如...

    使用 Apache MINA 开发高性能网络应用程序

    当客户端连接并发送数据时,服务器通过 `ProtocolCodecFilter` 解析数据,然后将接收到的数据原样返回给客户端,实现了简单的回显服务。 总结来说,Apache MINA 是一个强大的工具,它降低了开发高性能网络应用的...

Global site tag (gtag.js) - Google Analytics