---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
Java语言提供了丰富的网络编程类库,因此它非常适合用于网络编程,强大快捷的网络编程功能正是java备受欢迎的主要原因之一 。Java的网功能有几个不同的包实现,基本的网络功能定义在Java.net包中。 本文重点介绍Socket、DatagramSocket,讲解他们在网络编程中的重要作用。
通信协议是计算机网络通信的基础,它是计算机之间实现信息交换的一种约定。通过对网络协议进行分层可以简化协议的设计和实现。ISO组织的OSI模型将网络通信工作分为七层。但是由于OSI模型太复杂,目前的Internet所使用的标准特定的网路功能,其对照图如下:
在这四层结构中,比较常见的协议有如下几种:
1)IP协议:即网际协议。IP协议能够接受网络接口层传过来的数据,封装成数据包,交由传输层传输。
2)TCP协议:即传输控制协议,TCP协议提供了一种面向连接的、可靠的字节流服务。因此通信双方彼此交换数据前必须建立一 个 TCP连接。TCP通过一些手段来确保数据传输的完整。
3)UDP协议: 即用户数据报协议。UDP是一种无连接的传输层协议,提供面向事务的、简单不可靠的数据传送服务。
4)HTTP:即超文本传输协议。HTTP是从WWW服务器传输超文本到本地浏览器的传输协议,他可以使浏览器高效的浏览各种网页信息。
5)FTP:即文本传输协议。FTP用于控制网络节点间文件的双向传输。
6)SMTP:即简单邮件传输协议。仅负责通过邮件传输文件,而不考虑文件的接收。
套接字(Socket)是网络上网络上运行的两个不同主机的进程间进行双向通信的端点,用于建立两个不同应用程序之间通过网络进行通信的信道。一般来说,位于不同主机的应用进程之间要在网络环境下进行通信,必须要在网络的每一端都要建立一个套接字。两个套接字之间可以是有链接的,也可以是无连接的,并通过套接字的读、写操作实现网络通信功能。
套接字由IP地址和端口组成。它既可以接收请求,也可以发送请求,因此利用它可以较为方便地编写网络上数据传输的程序。根据传输的数据类型的不同,套接字可以分为连接的数据流套接字和无连接的数据报套接字两种类型。其中,TCP套接字是面向连接的套接字的代表,UDP套接字是无连接数据报套接字的代表。
一、UDP传输方式
在Java的Java.net包中定义的两个类:DatagrameSocket 和 DatagramPacket,它们为应用程序中采用数据报通信方式进行网络通信提供了支持。
类 DatagramSocket
此类表示用来发送和接收数据报包的套接字。
数据报套接字是包投递服务的发送或接收点。
每个在数据报套接字上发送或接收的包都是单独编址和路由的。
从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
在DatagramSocket上总是启用UDP广播发送。
为了接收广播包,应该将 DatagramSocket 绑定到通配符地址。
在某些实现中,将 DatagramSocket 绑定到一个更加具体的地址时广播包也可以被接收。
构造方法:
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port, InetAddress laddr) 创建数据报套接字,将其绑定到指定的本地地址。
DatagramSocket(SocketAddress bindaddr) 创建数据报套接字,将其绑定到指定的本地套接字地址。
构造方法中的参数:
port - 要使用的端口。
laddr - 要绑定的本地地址
bindaddr - 要绑定的本地套接字地址,对于未绑定的套接字为 null。
方法:
close() 关闭此数据报套接字。
getPort() 返回此套接字的端口。
isBound() 返回套接字的绑定状态。
isClosed() 返回是否关闭了套接字。
disconnect() 断开套接字的连接。
isConnected() 返回套接字的连接状态。
getLocalPort() 返回此套接字绑定的本地主机上的端口号。
getInetAddress() 返回此套接字连接的地址。
send(DatagramPacket p) 从此套接字发送数据报包
getLocalSocketAddress() 返回此套接字绑定的端点的地址,如果尚未绑定则返回 null。
getRemoteSocketAddress() 返回此套接字连接的端点的地址,如果未连接则返回 null。
receive(DatagramPacket p) 从此套接字接收数据报包。
connect(SocketAddress addr) 将此套接字连接到远程套接字地址(IP 地址 + 端口号)。
connect(InetAddress address, int port) 将套接字连接到此套接字的远程地址。
类 DatagramPacket
此类表示数据报包。
数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。
从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。
构造方法:
DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int offset, int length) 构造 DatagramPacket,用来接收长度为 length 的包,在缓冲区中指定了偏移量。
DatagramPacket(byte[] buf, int length, SocketAddress address) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
方法:
getPort(int) 返回某台远程主机的端口号。
getData(byte[] ) 返回数据缓冲区。
getLength(int) 返回将要发送或接收到的数据的长度。
getOffset(int ) 返回将要发送或接收到的数据的偏移量。
getAddress() 返回某台机器的IP地址。InetAddress
getSocketAddress() 获取要将此包发送到的或发出此数据报的远程主机的SocketAddress。
setData(byte[] b) 为此包设置数据缓冲区。
setLength(int len) 为此包设置长度。
setPort(int iport) 设置要将此数据报发往的远程主机上的端口号。
setAddress(InetAddress iaddr) 设置要将此数据报发往的那台机器的IP 地址。
例:通过udp传输方式,将一段文字数据发送出去
<span style="font-size:14px;">import java.net.*;
class UdpSentDemo1 {
public static void main(String[] args) throws Exception {
//1、创建UDP服务,通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket();
//2、确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port)
byte[] data="UDP Is Coming".getBytes();
DatagramPacket dp=new DatagramPacket(data,data.length,InetAddress.getByName("220.181.111.86"),8000);
//3、通过socket服务,将已有的数据包发送出去,通过send方法
ds.send(dp);
//4、关闭资源
ds.close();
}
}</span>
例:定义一个应用程序,用于接收UDP协议传输的数据并处理
<span style="font-size:14px;">/*
思路:
1、定义udpsocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义数字标识。
方便于那些数据过来,该应用程序可以处理
2、定义一个数据包,因为要存储接收到的字节数据。
因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3、通过socket服务的receive方法将接受到的数据存入已定义好的数据包中。
4、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。
5、关闭资源
*/
import java.net.*;
import java.io.*;
class UdpReceiveDemo2 {
public static void main(String[] args) throws Exception {
//1、创建udp的socket服务,建立端点
DatagramSocket da=new DatagramSocket(8000);
BufferedWriter bufw=new BufferedWriter(new FileWriter("info.txt"));
while(true){
//2、定义一个数据包用于存储数据
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//3、通过socket方法receive接收
da.receive(dp);
//4、分解手数据包
String id=dp.getAddress().getHostAddress();
//System.out.println(id);
String data=new String(dp.getData(),0,dp.getLength());
//System.out.println(data);
Integer port=new Integer(dp.getPort());
bufw.write(id);
bufw.newLine();
bufw.write(data);
bufw.newLine();
bufw.write(port.toString());
bufw.newLine();
bufw.flush();
//System.out.println(id+".."+data+"..."+port);
}
//5、关闭资源
//bufw.close();
//da.close();
}
}</span>
二、TCP传输方式
Stream Socket套接字用于在主机和Internet之间建立可靠的、双向的、持续的、点对点的流式连接。TCP套接字是面向连接的套接字的代表。
TCP通信中与Socket通信相关的两个类:一个是代表服务器端套接字的ServerSocket类,另一个是代表客户端套接字的Socket类。
类 ServerSocket
服务器套接字
服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
服务器套接字的实际工作由 SocketImpl 类的实例执行。应用程序可以更改创建套接字实现的套接
字工厂来配置它自身,从而创建适合本地防火墙的套接字。
构造方法:
ServerSocket() 创建非绑定服务器套接字。
ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog) 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr) 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
构造方法参数:
port - 本地 TCP 端口
backlog - 侦听 backlog
bindAddr - 要将服务器绑定到的 InetAddress
方法:
void close() 关闭此套接字。
Socket accept() 侦听并接受到此套接字的连接。
boolean isBound() 返回ServerSocket的绑定状态。
boolean isClosed() 返回ServerSocket的关闭状态。
String toString() 作为String返回此套接字的实现地址和实现端口。
int getLocalPort() 返回此套接字在其上侦听的端口。
InetAddress getInetAddress() 返回此服务器套接字的本地地址。
SocketAddress getLocalSocketAddress( null) 返回此套接字绑定的端点的地址,如果尚未绑定则返回。
void bind(SocketAddress endpoint) 将ServerSocket绑定到特定地址(IP 地址和端口号)。
void bind(SocketAddress endpoint, int backlog) 将ServerSocket绑定到特定地址(IP 地址和端口号)。
方法中的参数:
endpoint - 要绑定的 IP 地址和端口号。
backlog - 侦听 backlog 长度。
类 Socket
此类实现客户端套接字(也可以就叫“套接字”)。
套接字是两台机器间通信的端点。 套接字的实际工作由 SocketImpl 类的实例执行。
应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。
构造方法:
Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程地址上的指定远程端口。
Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口
构造方法参数:
port - 端口号。
address - IP 地址。
localAddr - 要将套接字绑定到的本地地址
localPort - 要将套接字绑定到的本地端口
host - 主机名,或者为 null,表示回送地址。
方法:
void close() 关闭此套接字。
boolean isBound() 返回套接字的绑定状态。
boolean isClosed() 返回套接字的关闭状态。
String toString() 将此套接字转换为 String。
int getPort() 返回此套接字连接到的远程端口。
int getLocalPort() 返回此套接字绑定到的本地端口。
void shutdownOutput() 禁用此套接字的输出流。
InetAddress getInetAddress() 返回套接字连接的地址。
InputStream getInputStream() 返回此套接字的输入流。
OutputStream getOutputStream() 返回此套接字的输出流。
void connect(SocketAddress endpoint) 将此套接字连接到服务器。
演示TCP传输:
/*
客户端
*/
import java.net.*;
import java.io.*;
class TcpClient {
public static void main(String[] args) throws Exception{
//创建客户端的Socket服务,指定目的主机和端口
Socket s=new Socket("192.168.1.104",10003);
//为了发送数据,应该获取Socket流中的输出流,通过getOutputStream();
OutputStream out=s.getOutputStream();
out.write("Tcp Demo".getBytes());
s.close();
}
}
/*
服务器端
*/
class TcpServer {
public static void main(String[] args) throws Exception{
//建立服务端Socket服务,并监听一个端口。
ServerSocket ss=new ServerSocket(10003);
//通过accept方法获取连接过来的客户端对象。
Socket s=ss.accept();
//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
//关闭客户端资源
s.close();
}
}
演示Tcp的传输客户端的互访:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
import java.net.*;
import java.io.*;
class TcpClient {
public static void main(String[] args) throws Exception{
Socket s=new Socket("192.168.1.104",10004);
OutputStream out=s.getOutputStream();
out.write("从客户端发过来的数据".getBytes());
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
//服务端
class TcpServer {
public static void main(String[] args)throws Exception{
ServerSocket ss=new ServerSocket(10004);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"is connected");
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
OutputStream out=s.getOutputStream();
out.write("收到你发来的数据".getBytes());
}
}
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------