首先来了解UDP协议的几个特性
(1)UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当UDP它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
(2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
(4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。 (5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表(这里面有许多参数)。 (6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
UDP是无状态的,之前的做的TCP接到客户端请求后马上做一个线程,将连接对象传递进去进行处理!
但是UDP的话是没有连接对象的,只要消息包的概念!
这就好像两个人在一条河边干活,TCP是架桥搬运货物,而UDP是直接把货物仍过去了,至于货物是否到达只能通过对岸的人喊一声收到了!
这里我模拟的时候收到的消息包就直接做一个线程进行处理了,理想的话应该是根据客户端的地址来创建线程!
这样的话就好像每个客户端都有自己的链路了一样,总服务端服务收包,然后根据包是给谁的就扔给某线程去处理!这和快递公司的处理流程差不多,总站是总服务端,而快递员是子服务端!
来看一下代码:
package udpUpload; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; import java.util.Arrays; /** * @说明 UDP连接服务端,这里一个包就做一个线程处理 * @author 崔素强(http://cuisuqiang.iteye.com/) * @version 1.0 * @since */ public class UdpService { public static void main(String[] args) { try { init(); while(true){ try { byte[] buffer = new byte[1024 * 64]; // 缓冲区 DatagramPacket packet = new DatagramPacket(buffer, buffer.length); receive(packet); new Thread(new ServiceImpl(packet)).start(); } catch (Exception e) { } Thread.sleep(1 * 1000); } } catch (Exception e) { e.printStackTrace(); } } /** * 接收数据包,该方法会造成线程阻塞 * @return * @throws Exception * @throws IOException */ public static DatagramPacket receive(DatagramPacket packet) throws Exception { try { datagramSocket.receive(packet); return packet; } catch (Exception e) { throw e; } } /** * 将响应包发送给请求端 * @param bt * @throws IOException */ public static void response(DatagramPacket packet) { try { datagramSocket.send(packet); } catch (Exception e) { e.printStackTrace(); } } /** * 初始化连接 * @throws SocketException */ public static void init(){ try { socketAddress = new InetSocketAddress("localhost", 2233); datagramSocket = new DatagramSocket(socketAddress); datagramSocket.setSoTimeout(5 * 1000); System.out.println("服务端已经启动"); } catch (Exception e) { datagramSocket = null; System.err.println("服务端启动失败"); e.printStackTrace(); } } private static InetSocketAddress socketAddress = null; // 服务监听个地址 private static DatagramSocket datagramSocket = null; // 连接对象 } /** * @说明 打印收到的数据包,并且将数据原封返回,中间设置休眠表示执行耗时 * @author 崔素强(http://cuisuqiang.iteye.com/) * @version 1.0 * @since */ class ServiceImpl implements Runnable { private DatagramPacket packet; public ServiceImpl(DatagramPacket packet){ this.packet = packet; } public void run() { try { byte[] bt = new byte[packet.getLength()]; System.arraycopy(packet.getData(), 0, bt, 0, packet.getLength()); System.out.println(packet.getAddress().getHostAddress() + ":" + packet.getPort() + ":" + Arrays.toString(bt)); Thread.sleep(5 * 1000); // 5秒才返回,标识服务端在处理数据 // 设置回复的数据,原数据返回,以便客户端知道是那个客户端发送的数据 packet.setData(bt); UdpService.response(packet); } catch (Exception e) { e.printStackTrace(); } } }
这里子服务端中间停留了五秒钟,这是模拟程序正在处理,处理完毕后再拿一些数据通过总服务端连接对象仍出去!
因为消息包内是包含客户端连接进来时的连接信息的,所以这里只需要设置要回复的数据即可!
我们再来看一下客户端,为了更形象模拟多客户访问的场景,这里客户端是一些子线程来完成,每个线程都有自己的连接对象,IP 一样但是端口不一样!
来看一下代码:
package udpUpload; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.util.Arrays; import java.util.Random; import java.util.UUID; /** * @说明 UDP连接客户端 * @author 崔素强(http://cuisuqiang.iteye.com/) * @version 1.0 * @since */ public class UdpClient { public static void main(String[] args) { try { for(int i=0;i<5;i++){ new Thread(new ClientImpl()).start(); } } catch (Exception e) { e.printStackTrace(); } } } /** * @说明 线程创建自己的UDP连接,端口动态,发送一组数据然后接收服务端返回 * @author 崔素强(http://cuisuqiang.iteye.com/) * @version 1.0 * @since */ class ClientImpl implements Runnable{ private Random random = new Random(); private String uuid = UUID.randomUUID().toString(); public void run() { try { init(); byte[] buffer = new byte[1024 * 64]; // 缓冲区 // 发送随机的数据 byte[] btSend = new byte[]{(byte)random.nextInt(127), (byte)random.nextInt(127), (byte)random.nextInt(127)}; DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 2233); packet.setData(btSend); System.out.println(uuid + ":发送:" + Arrays.toString(btSend)); try { sendDate(packet); } catch(Exception e){ e.printStackTrace(); } receive(packet); byte[] bt = new byte[packet.getLength()]; System.arraycopy(packet.getData(), 0, bt, 0, packet.getLength()); if(null != bt && bt.length > 0){ System.out.println(uuid + ":收到:" + Arrays.toString(bt)); } Thread.sleep(1 * 1000); } catch (Exception e) { e.printStackTrace(); } } /** * 接收数据包,该方法会造成线程阻塞 * @return * @throws IOException */ public void receive(DatagramPacket packet) throws Exception { try { datagramSocket.receive(packet); } catch (Exception e) { throw e; } } /** * 发送数据包到指定地点 * @param bt * @throws IOException */ public void sendDate(DatagramPacket packet) { try { datagramSocket.send(packet); } catch (Exception e) { e.printStackTrace(); } } /** * 初始化客户端连接 * @throws SocketException */ public void init() throws SocketException{ try { datagramSocket = new DatagramSocket(random.nextInt(9999)); datagramSocket.setSoTimeout(10 * 1000); System.out.println("客户端启动成功"); } catch (Exception e) { datagramSocket = null; System.out.println("客户端启动失败"); e.printStackTrace(); } } private DatagramSocket datagramSocket = null; // 连接对象 }
先运行服务端,然后运行客户端,来看一下打印信息:
服务端:
服务端已经启动 127.0.0.1:381:[56, 5, 1] 127.0.0.1:1569:[45, 43, 124] 127.0.0.1:9969:[36, 97, 117] 127.0.0.1:9937:[2, 110, 80] 127.0.0.1:3420:[48, 19, 80]
客户端:
客户端启动成功 客户端启动成功 客户端启动成功 客户端启动成功 客户端启动成功 6d62c2ae-e693-4e35-a295-9a385244cbf0:发送:[56, 5, 1] 49fa0ae9-59c3-4db9-97e7-930d9ada50fb:发送:[45, 43, 124] 3338ddd0-dfa1-4001-80b1-8e663f7d502f:发送:[36, 97, 117] 7b7fc365-e865-4b7c-bd8e-22a5ea095516:发送:[2, 110, 80] 53f2c5fc-3194-4e90-9c47-dbcbdef0ccc4:发送:[48, 19, 80] 6d62c2ae-e693-4e35-a295-9a385244cbf0:收到:[56, 5, 1] 49fa0ae9-59c3-4db9-97e7-930d9ada50fb:收到:[45, 43, 124] 3338ddd0-dfa1-4001-80b1-8e663f7d502f:收到:[36, 97, 117] 7b7fc365-e865-4b7c-bd8e-22a5ea095516:收到:[2, 110, 80] 53f2c5fc-3194-4e90-9c47-dbcbdef0ccc4:收到:[48, 19, 80]
请您到ITEYE网站看原创,谢谢!
http://cuisuqiang.iteye.com/ !
自建博客地址:http://www.javacui.com/ ,内容与ITEYE同步!
可以看到,客户端同时启动了五个端口与服务端通信!
服务端也收到了来自不同客户端的消息!
相关推荐
在这个主题中,我们将详细探讨如何使用Java进行UDP多线程服务端和简单客户端的编程,以及如何通过IP识别不同的客户端。 首先,让我们了解一下UDP的基础知识。UDP是一种无连接的传输层协议,不保证数据的顺序、可靠...
总的来说,这个C# UDP多线程多客户端传输例子展示了如何利用C#的套接字类和多线程技术实现高效的UDP通信。服务端通过监听端口并为每个客户端创建独立的处理线程,确保了并发处理能力;客户端则通过多线程发送和接收...
本文将深入探讨C#环境下如何实现UDP(User Datagram Protocol)服务端和客户端的通信,并通过一个实际的代码示例进行解析。 首先,理解UDP的基本特性至关重要。UDP是一种无连接的传输层协议,它不建立连接也不维护...
此外,对于多线程或多进程环境,还需要关注并发处理和同步问题。 为了深入理解这个示例,你可以打开这两个文件,查看它们是如何实现上述步骤的。同时,通过运行和调试代码,可以更直观地了解UDP通信的工作流程。...
在实际项目中,你可能需要根据具体需求对这些基础脚本进行扩展,例如添加错误处理、数据包序列化和反序列化、多线程优化等功能。同时,为了确保数据的正确性,你可能还需要设计一套自己的消息系统,包括消息ID、消息...
在"基于UDP协议的简单服务端和客户端示例"中,我们通常会看到以下关键概念和技术: 1. **UDP套接字**:在C++中,我们使用`socket()`函数创建UDP套接字,它允许程序收发UDP数据报。套接字分为两种类型:服务器端套接...
4. **多线程**:由于UDP通信可能会同时收到多个数据包,为了处理并发,服务端通常会在单独的线程或者异步操作中处理接收。 5. **数据编码与解码**:在发送和接收数据时,我们通常需要将字符串或者其他复杂类型的...
标题中的“udp 服务端和客户端,c++”指的是使用C++编程语言实现UDP(User Datagram Protocol)协议的服务端和客户端程序。UDP是传输层的一种无连接、不可靠的协议,常用于实时数据传输,如视频流、语音通话等场景。...
下面将详细解释C++中实现UDP服务端和客户端程序的关键知识点。 首先,了解UDP的基本概念至关重要。与TCP(传输控制协议)不同,UDP不保证数据包的顺序、完整性和可靠性,而是以尽可能快的速度发送数据,因此适用于...
3. 并发处理:服务器端可能需要同时处理多个客户端的请求,因此需要考虑并发编程和线程安全问题。 总的来说,TCP和UDP各有优劣,选择哪种协议取决于具体的应用需求。TCP适用于对数据完整性和可靠性要求高的场景,如...
此外,为了提高性能和处理多个客户端,服务端通常会使用多线程技术。QT提供了QThread类来支持多线程编程,每个连接或每个数据包的处理可以在单独的线程中进行,避免了主线程阻塞,提高了系统的响应速度。 总的来说...
本DEMO展示了如何在QT环境下使用UDP进行通信,即创建一个简单的UDP服务器和客户端,实现数据的双向传输。 首先,让我们从`main.cpp`开始。这个文件是程序的入口点,通常包含了应用的主要逻辑和窗口对象的实例化。在...
下面将详细介绍如何在C#中创建UDP服务端和客户端。 首先,我们来看服务端的实现。服务端的主要任务是监听特定的端口,等待来自客户端的数据包,并对收到的数据进行处理。以下是一个简单的服务端示例: 1. 创建一个...
5. 多线程编程,服务端可能需要同时处理多个客户端的连接请求,因此可能需要使用线程池或多线程技术。 总的来说,这个项目提供了一个学习和实践网络编程,特别是UDP通信的好机会。开发者可以通过查看和运行源代码,...
本教程将深入讲解如何使用C#和Winform创建一个简单的TCP服务器端和客户端通信工具。 首先,TCP(传输控制协议)是一种面向连接的、可靠的通信协议,它确保了数据的有序和无损传输。在C#中,我们通常使用`System.Net...
而《Linux多线程服务端编程:使用muduo C++网络库》.(陈硕).[PDF]@ckook.txt可能是一个配套的文本文件,可能是书中的代码示例或者补充资料,帮助读者更好地理解和实践书中所讲的知识。 总之,这本书对于希望提升...
在这个"UDP协议客户-服务端字符串转发模型"中,我们将深入探讨如何在Linux环境下利用C语言编写客户端和服务器端程序,实现字符串的接收、转换和转发。 首先,我们有两个关键的源代码文件:`kclient.c.txt`和`...
线程池是一种多线程处理形式,预先创建一组线程,用于处理到达的I/O请求。当一个请求到达时,线程池中的空闲线程会被分配去处理,而不是每次都创建新的线程,这可以减少线程创建和销毁的开销。 在具体实现过程中,...
在这个场景中,"VBNET的UDP客户端和服务端源码"是两个实现UDP通信的示例项目,分别代表了UDP通信的两端:发送数据的客户端和接收数据的服务端。 WindowedUDPclient和WindowedUDPserver是这两个项目的源代码文件,...
为了处理多个客户端,服务端可能使用了多线程或者异步操作,确保每个客户端连接都能独立处理。 在"客户端"部分,开发者可能涉及以下步骤: 1. 创建ClientSocket:客户端也需要创建Socket实例,然后连接到服务端的IP...