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

基于Java的网络技术

2012-03-13 14:42 113 查看
TCP/IP套接字

套接字是网络软件中的一个抽象概念,套接字允许单个计算机同时服务于很多不同客户,并能够提供不同类型信息的服务。该技术由引入的端口处理,该端口既是一个特定机器上的一个被编号的套接字---通信端口.TCP/IP套接字用于在主机和Internet之间建立的可靠、双向、点对点、持续的流式连接。

在java中,TCP/IP Socket连接是用java.net包中的类实现的,这些类实现了建立网络连接和通过连接发送数据的复杂过程,我们只需使用其简单接口就能实现网络通信!在java中有两类套接字,一种是服务器端套接字--java.net.ServerSocket,另一种是客户端套接字--java.net.Socket。

ServerSocket

其中,ServerSocket被设计成在等待客户建立连接之前不做任何事情的监听器,构造方法的版本如下:

public ServerSocekt(int port) throws IOException

--在服务器指定端口port创建队列长度为50的服务器套接字,当port为0则代表创建一个基于任意可用端口的服务器套接字。队列长度告诉系统多少与之连接的客户在系统拒绝连接之前可以挂起。

public ServerSocekt(int port, int maxQueue) throws IOException

--在指定端口创建指定队列长度的服务器套接字

public ServerSocket(int port, int maxQueue, InetAddress bindAddr ) throws IOException

在多地址主机上,我们除了可以指定端口之外,还可以通过InetAddress类来指定该套接字约束的IP地址。InetAddress在后面将学习。

ServerSocket还定义了以下一些常用的方法:

public Socket accept() throws IOException

--该方法用于告诉服务器不停地等待,直到有客户端连接到该ServerSocket指定的端口,一旦有客户端通过网络向该端口发送正确的连接请求,该方法就会返回一个表示服务器与客户端连接已建立的Socket对象,接下来我们就可以通过这个返回的Socket对象实现服务器与指定客户端的通信。注意:accept()方法会让服务器中的当前线程暂停下来,直到有客户端的正确连接发送过来。

public void bind(SocketAddress endpoint) throws IOException

--绑定该ServerSocket到指定的endpoint地址(IP地址和端口)

public void close() throws IOException

--关闭当前ServerSocket。任何当前被锁定的线程将在accept()方法中抛出IOException。

从jdk1.4开始,java提供了关于ServerSocket的ServerSocketChannel,jdk建议用管道来实现客户端连接的监听以及关闭服务器套接字会更安全,因此,现在我们应该通过ServerSocket来得到其套接字管道,通过管道来实现服务监听以及关闭,可以通过ServerSocket的getChannel()方法来得到当前ServerSocket的相关管道。

Socket

该类为建立连向服务器套接字及启动协议交换而设计,当进程通过网络进行通信的时候,java技术使用流模型来实现数据的通信。一个Socket包括两个流,分别为一个输入流和一个输出流,一个进程如果要通过网络向另一个进程发送数据,只需简单地写入与Socket相关联的输出流,同样,一个进程通过从与Socket相关联的输入流来读取另一个进程所写的数据。如果通过TCP/IP协议建立连接,则服务器必须运行一个单独的进程来等待连接,而某一客户机必须试图到达服务器,就好比某人打电话,必须保证另一方等待电话呼叫,这样才能实现两人之间的通信。

分析以下代码:

import java.io.*;
import java.net.*;
......
try{
// 在服务器的8000端口创建一个ServerSocket
ServerSocket server = new ServerSocket(8000);

// accept()方法使当前服务器线程暂停,之前创建的server套接字
//将通过该方法不停的监听指定端口是否有客户端请求连接发送过来,
//如果有正确连接发送过来,
// 则该方法返回一个表示连接已建立的Socket对象
Scoket fromSocket = server.accept();

if (fromSocket != null){
// 通过套接字实现数据传输,得到套接字的输入流输出流
InputStream input = fromSocket.getInputStream();
OutputStream out = fromSocket.getOutputStream();
}
}catch(IOException e){
e.printStackTrace();
}


......

通过上面的代码,我们分析得知,套接字只是实现数据传输的接口,真正实现数据传输的是封装在套接字中的输入、输出流。以上代码是服务器端程序,该程序开启了一个端口号为8000的特定端口,并且开启了服务器套接字在该端口上监听客户请求,accept()方法阻塞当前线程直到有客户端请求发送过来,当请求正确时,该方法将客户端套接字引用传递出来,这样,网络之间的数据发送就好像是本地数据调用。

Socket类的相关方法:

Socket()创建一个无参数套接字,该套接字会随即取一个可用端口、可用IP来建立连接。

Socket(String host, int port)创建一个指定远程服务器、端口号的套接字

Socket(InetAddress net, int port)创建一个指定InetAddress类封装IP、指定端口号的套接字。即该套接字只能往指定IP的服务器以及服务器指定端口发送数据。

public OutputStream getOutputStream() throws IOException 得到套接字的输出流,接下来就可以使用得到的输出流去写数据至服务器或客户端

public InputStream getInputStream() throws IOException得到套接字的输入流,接下来就可以使用得到的输入流去读取来自于服务器或客户端的数据。

public SocketChannel getChannel()得到套接字的管道,在1.4之后新增了io功能,在java.nio包中定义,通过流中的SocketChannel来实现数据的读取会比直接使用流来读取更安全可靠。(扩展内容)

public void close() throws IOException关闭当前套接字,注意,关闭套接字的同时也会关闭该套接字中的所有流。

下面是客户端的部分代码:

import java.io.*;
import java.net.*;
......
try{
// 创建套接字,该套接字连接IP地址为192.168.0.2的服务器,端口为8000			Socket server = new Socket("192.168.0.2",8000);

if(server != null){
// 通过套接字实现数据传输输入流
InputStream input = fromSocket.getInputStream();
OutputStream out = fromSocket.getOutputStream();
}
}catch(IOException e){
e.printStackTrace();
}


以上即是简单的基于Tcp/IP协议、使用套接字实现数据传输的服务器和客户端代码(注意:在运行时,先执行服务器端代码,接着执行客户端代码),但是我们发现,通过以上代码,客户端和服务器端只能进行一次数据对话,通过更改以上代码,我们才能实现一个客户端与服务器端的真正对话,直到某一方终止通话为止,修改后代码如下:

服务器端:

......
ServerSocket server = new ServerSocket(8000);
while (true){
Socket fromSocket = server.accept();
if (fromSocket != null){
InputStream input = fromSocket.getInputStream();
OutputStream out = fromSocket.getOutputStream();
.....
}
}
.....


客户端:

......
Socket server = new Socket("192.168.0.2",8000);
InputStream input = fromSocket.getInputStream();
OutputStream out = fromSocket.getOutputStream();

while (true){
// 数据的读写操作
......
}
......


实际上,我们只要将服务器端每一个客户的请求套接字的获取以及流的获取、数据的读写放入至一个无限循环,这样就可以保证服务器可以随时接受任意客户发送过来的套接字,从而实现对话。客户端也可以通过一个无限循环实现对服务器端的任意时刻的数据传输。

当然,这只是实现了一个客户和服务器之间的对话,但是服务器一般是对应许多客户的,因此,为了实现服务器对应多个客户,必须将每一次accept()方法返回的每一个客户套接字保存起来,这样才可以实现服务器与多个客户对应,具体代码在后面讨论。

注意,数据的读写应该是在一个独立于主线程的单独线程中运行,因为accept方法会阻塞当前线程,为了不影响主线程的其余功能,我们应该启用多线程来实现高效的数据传输。

当通过代码实现服务器与客户之间的套接字发送之后,我们就可以使用流的IO操作来实现服务器与客户端之间的基于特定协议的远程数据传输。注意,基于TCP/IP协议的数据传输,前提是必须得保证接受数据的一方是连通的,也就是说,如果服务器端没有运行,那么客户端是无法对其发送信息,反之亦然。那有时候我们只在乎信息的发送,并不理会接受的人是否连通,甚至不理会接受人是否存在,那就不能使用TCP/IP协议,而得通过我们下面所学的UDP协议来实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: