![疯狂Java讲义:使用DatagramSocket发送、接收数据[2],第1张 疯狂Java讲义:使用DatagramSocket发送、接收数据[2],第1张](/aiimages/%E7%96%AF%E7%8B%82Java%E8%AE%B2%E4%B9%89%EF%BC%9A%E4%BD%BF%E7%94%A8DatagramSocket%E5%8F%91%E9%80%81%E3%80%81%E6%8E%A5%E6%94%B6%E6%95%B0%E6%8D%AE%5B2%5D.png)
程序客户端代码也与此类似 客户端采用循环不断地读取用户键盘输入 每当读到用户输入内容后就将该内容封装成DatagramPacket数据报 再将该数据报发送出去 接着把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该DatagramPacket所封装的字节数组中) 客户端代码如下
程序清单 codes/ / /UdpClient java
public class UdpClient
{
//定义发送数据报的目的地
public static final int DEST_PORT =
public static final String DEST_IP =
//定义每个数据报的最大大小为 K
private static final int DATA_LEN =
//定义该客户端使用的DatagramSocket
private DatagramSocket socket = null
//定义接收网络数据的字节数组
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
{
try
{
//创建一个客户端DatagramSocket 使用随机端口
socket = new DatagramSocket()
//初始化发送用的DatagramSocket 它包含一个长度为 的字节数组
outPacket = new DatagramPacket(new byte[ ]
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
inPacket getLength()))
}
}
//使用finally块保证关闭资源
finally
{
if (socket != null)
{
socket close()
}
}
}
public static void main(String[] args)
throws IOException
{
new UdpClient() init()
}
}
上面程序的粗体字代码同样也是通过DatagramSocket发送 接收DatagramPacket的关键代码 这些代码与服务器的代码基本相似 而客户端与服务器端的唯一区别在于 服务器所在IP地址 端口是固定的 所以客户端可以直接将该数据报发送给服务器 而服务器则需要根据接收到的数据报来决定将 反馈 数据报的目的地
读者可能会发现 使用DatagramSocket进行网络通信时 服务器端无须 也无法保存每个客户端的状态 客户端把数据报发送到服务器后 完全有可能立即退出 但不管客户端是否退出 服务器无法知道客户端的状态
当使用UDP协议时 如果想让一个客户端发送的聊天信息可被转发到其他所有客户端则比较困难 可以考虑在服务器使用Set来保存所有客户端信息 每当接收到一个客户端的数据报之后 程序检查该数据报的源SocketAddress是否在Set集合中 如果不在就将该SocketAddress添加到该Set集合中 但这样一来又涉及一个问题 可能有些客户端发送一个数据报之后永久性地退出了程序 但服务器端还将该客户端的SocketAddress保存在Set集合中……总之 这种方式需要处理的问题比较多 编程比较烦琐 幸好Java为UDP协议提供了MulticastSocket类 通过该类可以轻松实现多点广播
返回目录 疯狂Java讲义
编辑推荐
Java程序性能优化 让你的Java程序更快 更稳定
新手学Java 编程
Java程序设计培训视频教程
lishixinzhi/Article/program/Java/hx/201311/27260pubic void close() 当我们创建一个套接字后,用该方法关闭套接字。
public int getLocalPort() 返回本地套接字的正在监听的端口号。
public void receive(DatagramPacket p) 从网络上接收数据包并将其存储在DatagramPacket对象p中。p中的数据缓冲区必须足够大,receive()把尽可能多的数据存放在p中,如果装不下,就把其余的部分丢弃。接收数据出错时会抛出IOException异常。
public Void Send(DatagramPacket p) 发送数据包,出错时会发生IOException异常。
姓名:罗学元 学号:21181214375 学院:广州研究院【嵌牛导读】Linux进程间套接字通信基础
【嵌牛鼻子】Linux 进程间套接字及通信介绍
【嵌牛提问】Linux进程间套接字包含哪些内容,如何实现通信
一、套接字(Socket)通信原理
套接字通信允许互联的位于不同计算机上的进程之间实现通信功能。
二、套接字的属性
套接字的特性由3个属性确定,它们分别是:域、类型和协议。
1. 套接字的域
它指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址和端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接。
另一个域AF_UNIX表示UNIX文件系统,就是文件输入/输出,它的地址就是文件名。
2. 套接字类型
因特网提供了两种通信机制:流(stream)和数据报(datagram),因而套接字的类型也就分为流套接字和数据报套接字。我们主要看流套接字。
流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。
流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。
与流套接字相对的是由类型SOCK_DGRAM指定的数据报套接字,它不需要建立连接和维持一个连接,它们在AF_INET中通常是通过UDP/IP实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它并不需要总是要建立和维持一个连接。
3.套接字协议
只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。
三、套接字地址
每个套接字都有其自己的地址格式,对于AF_UNIX域套接字来说,它的地址由结构sockaddr_un来描述,该结构定义在头文件
struct sockaddr_un{
sa_family_t sun_family //AF_UNIX,它是一个短整型
char sum_path[] //路径名
}
对于AF_INET域套接字来说,它的地址结构由sockaddr_in来描述,它至少包括以下几个成员:
struct sockaddr_in{
short int sin_family //AN_INET
unsigned short int sin_port //端口号
struct in_addr sin_addr //IP地址
}
而in_addr被定义为:
struct in_addr{
unsigned long int s_addr
}
四、基于流套接字的客户/服务器的工作流程
使用socket进行进程通信的进程采用的客户/服务器系统是如何工作的呢?
1.服务器端
首先,服务器应用程序用系统调用socket来创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他的进程共享。
接下来,服务器进程会给套接字起个名字,我们使用系统调用bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。
然后,系统调用listen来创建一个队列,并将其用于存放来自客户的进入连接。
最后,服务器通过系统调用accept来接受客户的连接。它会创建一个与原有的命名套接不同的新套接字,这个套接字只用于与这个特定客户端进行通信,而命名套接字(即原先的套接字)则被保留下来继续处理来自其他客户的连接。
2.客户端
基于socket的客户端比服务器端简单。同样,客户应用程序首先调用socket来创建一个未命名的套接字,然后讲服务器的命名套接字作为一个地址来调用connect与服务器建立连接。
一旦连接建立,我们就可以像使用底层的文件描述符那样用套接字来实现双向数据的通信。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)