您的位置:首页 > 理论基础 > 计算机网络

黑马程序员--10.网络编程--05.【TCP协议相关类】【InetSocketAddress类】【Socket类】【ServerSocket类】【TCP客户端和服务器端】

2013-08-28 21:33 781 查看

网络编程--5

TCP协议相关类

 InetSocketAddress类

Socket类

ServerSocket类

 TCP客户端和服务器端

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------
Socket通信端点具备了,但是数据传输协议不一样的。因此每一种数据传输协议都有自己特有创建Socket通信端点方法TCP协议有自己创建Socket通信端点的方法

1.    UDP协议相关类

UDP协议相关类的综述

(1). TCP和UDP创建的Socket通信端点的类型

[1]. UDP协议是面相无连接的协议。创建数据传输两个Socket通信端点用的是同一个DatagramSocket类进行创建的。因此UDP通信不区分通信双方的主次

[2]. TCP协议是面相连接的协议。创建数据传输两个Socket通信端点用的并不是同一个Socket类通信的一方程序称为服务器Socket端点,使用ServerSocket类进行创建。通信的另一方程序称为客户端Socket端点,使用Socket类进行创建。

(2). TCP和UDP传输数据的类型

[1]. UDP协议是数据的传输形式数据报包数据byte[]被DatagramPacket类封装成数据报包通信端点之间进行传输


【注意】Datagram Socket数据报Socket -----因为UDP的数据通过数据报DatagramPacket传输的,因此UDP中的Socket端点称为数据报Socket(Datagram Socket)

[2]. TCP协议是数据的传输形式IO网络流没有特殊的类数据进行封装,直接使用IO网络流对通行端点的数据进行传输。

【注意】Stream Socket网络流Socket -----因为TCP的数据通过网络流传输的,因此TCP中的Socket端点称为网络流Socket
(Stream Socket)


通过DatagramSocket创建的Socket端点称为数据报Socket

结论】TCP通信中相关的类就是ServerSocket类Socket类

2.    java.net.InetSocketAddress类

1). SocketAddress抽象类

SocketAddress抽象类

[1]. SocketAddress抽象类所在的位置

SocketAddress位于java.net包

[3]. SocketAddress类的直接父类

SocketAddress类的直接父类java.lang.Object类

[4]. SocketAddress类的源码声明

public abstract class SocketAddress implements java.io.Serializable {}【注意】SocketAddress类中没有任何方法
[5]. SocketAddress类的含义

对主机的IP和需要进行网络通信的App所对应的端口的封装。因此SocketAddress就可以理解为IP和port的封装。

2). InetSocketAddress类(简介)

[1]. InetSocketAddress抽象类所在的位置

InetSocketAddress位于java.net包

[3]. InetSocketAddress类的直接父类

InetSocketAddress类的直接父类java.net.SocketAddress抽象类

[4]. InetSocketAddress类的含义

这个类实现了一个含有IP地址+PortSocketAddress。注意这个IP地址可以通过String类型主机名hostname被解析成IP地址。因此InetAddress对主机的IP和需要进行网络通信的App所对应的端口的封装。因此Inet
SocketAddress同样可以理解为IP和port的封装。

3.    java.net.Socket类

1). Socket类基础知识

(1). Socket类

[1]. Socket类所在的位置

Socket位于java.net包

[3]. Socket类的直接父类

Socket类的直接父类java.lang.Object类

[4]. Socket类的源码声明

public class Socket {
//...
}
[5]. Socket类的含义
两台主机间通信的端点(称客户端Socket端点或者Socket端点),实现了客户端的套接字。

(2). Socket类的构造方法

[1]. Socket构造方法中参数推断

{1}. 由于TCP通信在Java中的数据直接通过网络IO流进行传输IO中的数据没有办法对传输的目的主机IP和端口进行封装。

{2}. 通信端点双方可以互相通信(收和发),所以必须在Socket的构造方法指定创建的Socket的时候,就务必要指定这个Socket要绑定的主机(IP+
Port)
要通信目标主机(IP+Port)

【Socket要绑定的主机】指的是通信端点Socket所在的App所在的主机

注意】由于TCP数据传输协议面向连接的,所以网络流Socket实例化的时候一定要指定目标主机的SocketAddress
(面向连接的体现)。

[1]. Socket类中的核心private构造函数

{1}. 构造方法原型

private Socket(SocketAddress address, SocketAddresslocalAddr, boolean stream) throws IOException;
{2}. 构造方法的参数

{2}1. SocketAddressaddress: 指定通信的目标主机App的SocketAddress

{2}2. SocketAddresslocalAddr: 绑定Socket所在的主机App的SocketAddress

{2}3. boolean stream:

true ----创建网络流Socket(StreamSocket)

false ----创建数据报Socket(DatagramSocket)

[2]. String 主机名,int端口号

{1}. 构造函数原型

public Socket(String host, int port){2}. 构造方法的参数
{2}1. String host: 通过字符串形式指定通信的目标主机的IP

{2}2. int port: 目标主机的App对应的端口号

{3}. 和private构造方法的关系

public Socket(String host, int port) throws UnknownHostException, IOException{
this(
//传入目标主机的SocketAddress
host != null ? new InetSocketAddress(host, port) : new InetSocketAddress(InetAddress.getByName(null), port),
//传入Socket被绑定的主机的SocketAddress ----传入null 系统自行解析本机
//的SocketAddress
(SocketAddress) null,
//创建网络流Socket
true
);

[2]. InetAddress 主机地址,int端口号

{1}. 构造函数原型

public Socket(InetAddress address, int port)

{2}. 构造方法的参数
{2}1. InetAddress address:指定通信的目标主机的IP

{2}2. int port: 目标主机的App对应的端口号

{3}. 和private构造方法的关系

public Socket(String host, int port) throws UnknownHostException, IOException{
this(
//传入目标主机的SocketAddress
address != null ? new InetSocketAddress(address, port) : null,
//传入Socket被绑定的主机的SocketAddress ----传入null 系统自行解析本机
//的SocketAddress
(SocketAddress) null,
//创建网络流Socket
true
);
}


[3]. String 主机名,int端口号 || String 主机名,int端口号
public Socket(String host,
int port, InetAddress localAddr,
int localPort) throws IOException;
{2}. 构造方法的参数

{2}1. host + port:指定通信的目标主机的IP +目标主机App对应的端口号

{2}2.: localAddr + localPort: 指定本机的SocketAddress

{3}. 和private构造方法的关系

public Socket(String host, int port) throws UnknownHostException, IOException{
this(
//传入目标主机的SocketAddress
host != null ? new InetSocketAddress(host, port) : new InetSocketAddress(InetAddress.getByName(null), port),
//传入Socket被绑定的主机的SocketAddress
new InetSocketAddress(localAddr,localPort),
//创建网络流Socket
true
);
}[4]. InetAddress 主机IP,int端口号 ||InetAddress 主机名,int端口号
{1}. 构造函数原型

public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException;
{2}. 构造方法的参数

{2}1. address + port:指定通信的目标主机的IP +目标主机App对应的端口号

{2}2.: localAddr + localPort: 指定本机的SocketAddress

{3}. 和private构造方法的关系

public Socket(String host, int port) throws UnknownHostException, IOException{
this(
//传入目标主机的SocketAddress
address != null ? new InetSocketAddress(address, port) : null,
//传入Socket被绑定的主机的SocketAddress
new InetSocketAddress(localAddr,localPort),
//创建网络流Socket
true
);
}


[5]. 空参构造函数
{1}. 构造函数原型

public Socket() throws IOException;

{2}. 使用注意事项
一旦初始化完毕,就要立刻用过相应的方法去连接目标SocketAddress。通过方法void connect(SocketAddress endPoint)来连接目标主机的SocketAddress

2). Socket类负责通信的方法

由于TCP传输通过IO网络流进行传输,没有名字叫做send和receive的方法。通过输入流和输出流的方式进行数据传输。

(1). 获取网络输入流 ----用于通信双方的“接收”

[1]. 方法功能描述

返回这个客户端Socket通信端点网络输入流

[2]. 方法原型

public InputStream getInputStream() throws IOException;


[3]. 获取Socket输入作用
可以通过这个输入流从Socket读取字节数据byte[ ]

(2). 获取网络输出流 ----用于通信双方的“发送”

[1]. 方法功能描述

返回这个客户端Socket通信端点网络输入流

[2]. 方法原型

public InputStream getInputStream() throws IOException;


[3]. 获取Socket输出作用
可以通过这个输出流向Socket写入字节数据byte[ ]

总结】如果这个Socket服务端的Socket有一个相关联数据传输通道,那么通过返回的输入流输出流可以进行各种对这个数据传输通道Socket相关联的各种操作

(3). 关闭客户端的Socket输入流

[1]. 方法功能描述

为该客户端Socket将输入流的状态设置为“流的末端”。这样操作之后不可以从这个输入流读取数据

[2]. 方法原型

public voidshutdownInput() throws IOException;


(4). 关闭客户端的Socket输出流
[1]. 方法功能描述

为这个Socket禁止掉输出流。调用这个方法之前写入输出流的数据都会被正常发送到目标地址。在调用这个关闭输出流之后任何对这个流的写操作都会引起IOException。

[2]. 方法原型

public void shutdownOutput()throws IOException;


3). Socket类获取常规信息方法
(1). 获取本机的IP地址和进行网络通信的端口号

[1]. 获取本机的IP地址

public InetAddress getLocalAddress();


[2]. 获取本机的进行网络通讯的App的端口号
public int getLocalPort();


[3]. 获取本机的进行网络通讯的App的Socket地址
public SocketAddress getLocalSocketAddress();


(2). 获取目标通信本机的IP地址和进行网络通信的端口号
[1]. 获取目标通信主机的IP地址

public InetAddress getInetAddress();


[2]. 获取目标通信主机的进行网络通讯的App的端口号
public int getPort();


[3]. 获取目标通信主机的进行网络通讯的App的Socket地址
public SocketAddress getRemoteSocketAddress();

4.    java.net.ServerSocket类

1). ServerSocket类基础知识

(1). ServerSocket类

[1]. ServerSocket类所在的位置

ServerSocket位于java.net包

[3]. ServerSocket类的直接父类

ServerSocket类的直接父类java.lang.Object类

[4]. ServerSocket类的源码声明

public class ServerSocket {
//...
}
[5]. ServerSocket类的含义
这个类实现了服务器端的Socket通信端点。这个服务器端的Socket端点等待来自网络中的其他客户端Socket端点请求

(2). ServerSocket类的构造方法

[1]. ServerSocket构造方法中参数推断

由于ServerSocket可以通过自身的accept方法获取对该服务端Socket通信端点访问的其他Socket端点获取的Socket类的端点可以获取到自身所在主机目标主机各种信息,因此ServerSocket的构造方法仅仅给出监听的本机的App的端口就可以了。

[1]. int port

{1}. 构造方法原型

public ServerSocket(int port) throws IOException;


{2}. 构造方法的参数
int port: ServerSocket要监听的本机的App的端口号。


[2. 空参构造函数
{1}. 构造函数原型

public ServerSocket() throws IOException;


{2}. 使用注意事项
一旦初始化完毕,就要立刻用过相应的方法去连接目标SocketAddress。通过方法void bind(SocketAddress endPoint)来连接目标主机的SocketAddress

2). Socket类负责通信的方法

获取向该服务器Socket发起请求的客户端Socket

[1]. 方法功能描述

监听连接到这个ServerSocket服务端连接接受这个连接(这个TCP连接通道就被建立)。连接完成之后返回和这个服务端Socket建立连接的客户端Socket副本

[2]. 方法原型

public Socket accept() throws IOException;


[3]. accept()方法是一个阻塞式方法
这个方法会一直阻塞直到有来自客户端的Socket这个ServerSocket之间的连接被创建。

3). ServerSocket类获取常规信息方法

获取本机的IP地址和进行网络通信的端口号

[1]. 获取ServerSocket所在本机的IP地址

public InetAddress getInetAddress();


[2]. 获取ServerSocket所监听的本机的进行网络通讯的App的端口号
public int getLocalPort();


[3]. 获取ServerSocket被绑定的本机的进行网络通讯的App的Socket地址
public SocketAddress getLocalSocketAddress();

5.    TCP接收端和发送端

1). TCP客户端 ----Socket充当

(1). TCP客户端的操作流程 ----这里仅仅发送数据

[1]. 创建TCPSocket服务,指定目的主机端口

[2]. 为了发送数据,通过getInputStream()方法获取客户端Socket中的输出流

[3]. 数据到输出流, 并随网络发送到对应主机

[4]. 关闭Socket资源 对应流资源不用关闭。这是因为Socket资源被释放之后,通过Socket本身获得的输出流也随着Socket资源的释放而释放

(2). TCP客户端发送数据代码示例

/*需求:给服务器端发送一个文本数据*/
import java.net.*;
import java.io.*;
class TcpClient{
public static void main(String[] args) throws Exception{
//1. 创建客户端Socket服务,指定目的主机和端口
Sockets =new Socket("127.0.0.1", 10003);

//2.为了发送数据,应该获取Socket中的输出流
OutputStreamout =s.getOutputStream();
//3.写数据到输出流,并随网络发送到对应主机
out.write("TCP is coming....".getBytes());

//4.关闭Socket资源对应的流资源不用关闭
s.close();
}
}


2). TCP服务器端 ----ServerSocket充当
(1). TCP接收端的操作流程 ----仅仅接收数据

[1]. 创建TCPServerSocket服务,指定要监听的端口

[2]. 通过ServerSocket对象的accept()获取来自客户端的Socket对象。

[3]. 通过获取到的客户端Socket对象的getInputStream()方法读取客户端发送的信息

[4]. 关闭ServerSocket资源【可选操作,一般情况下服务器端不会被关闭

(2). TCP服务器端接收数据代码示例

/*需求:定义端接收数据,并打印在控制台上*/
class TcpServer{
public static void main(String[] args) throws Exception{
//1.建立服务器端Socket服务,并监听一个端口
ServerSocketss =new ServerSocket(10003);
//2.通过accept方法来获取连接过来的客户端对象 Server端本身没有流
//必须使用客户端对象的流对象与客户端本身进行通讯
Sockets =ss.accept();
InputStreamin =s.getInputStream();
//获取客户端的IP
Stringip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected!");
byte[] buf =new byte[1024];
int len =in.read(buf);
System.out.println(new String(buf, 0, len));
//客户端一定要关闭客户端的Socket对象
s.close();
ss.close();//服务器端对象的关闭操作是可选的
}
}


3). 演示结果
(1). 错误的启动顺序

[1]. 由于TCP传输协议是面向连接的。所以不能随意启动某个Socket通信端

[2]. 启动客户端Socket再启动服务端ServerSocket  ------错误的启动顺序

此时客户端就会立刻去连接服务端。但是由于服务端的Socket没有被启动,所以面相连接TCP数据传输通道就不能形成。此时会抛出java.net.ConnectionException异常,TCP数据传输失败。



(2). 正确的启动顺序

[1]. 启动服务端ServerSocket再启动客户端Socket  ------正确的启动顺序

可行性分析】服务端的程序运行到accept()方法之后,没有发现connection接入。此时服务端的程序被阻塞暂停在那里等待。之后,客户端程序被启动并立刻去连接目标服务端。这时候发现服务端已经启动,就会建立传输通道。这时候,客户端服务端就可以进行通信了。因此这个启动顺序可行

[2]. TCP启动顺序UDP启动顺序对比

{1}. TCP的启动顺序务必启动服务端启动客户端。否则,程序直接抛出异常

{2}. UDP的启动顺序启动接收端再启动客户端但是不这么做,接收端无法接收到数据,但是程序不会发生异常

(3). 运行结果



----------- android培训java培训、java学习型技术博客、期待与您交流! ------------
 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐