一、 前言
最近想用Java写出一个能够进行远程通信的程序,不可避免地接触到了Socket编程,在这里我不详细介绍TCP/IP协议,有还没有接触过TCP/IP的同学请自行谷歌或者百度。因为数据在Internet中的传输是非常繁重的,而套接字(Socket)的出现,让我们不必去关心传输的繁重过程,我们只需把网络看做一个流,就像对文件一样进行操作。
二、套接字(socket)的概念
当两个主机的程序之间要通过网络进行套接字通信的时候,我们可以将这过程抽象成下面这张简图。
当两台主机的程序要通过网络进行通信的时候,不可避免的两台主机要都知道对方的“位置”,才能把信息传给对方,网络中用IP地址标识主机的地址,当信息能准确地在两台主机之间传输的时候,还要把信息传到对应的程序里面去才行,举个例子如果我在电脑上用QQ给你发信息,你却在电脑的微信上接受到了信息,那么就乱套了。网络中用端口号标识程序。
一个套接字都有自己的IP地址和端口号,两两套接字直接通过IP地址和端口号对应,这就保证了信息在两台主机的程序之间的准确传输。
在这种模式下主机A的程序将一段信息写进Socket1中,Socket1将信息发送给Socket2,Socket2将信息写入主机B的程序b中。
在利用套接字进行通信的时候,都是服务器和客户机之间进行通信。基于TCP/IP协议的Socket编程,两个套接字建立的链接都是可靠地,可靠的意思是说当数据在网络传输过程中出错时,数据会由发送方重新发送。
图二
如图二所示:利用套接字编程主要步骤如下
1、分别为服务器,客户机创建套接字,将两个套接字连接起来。
2、打开套接字的输入输出流。输入流用来接收对方套接字的数据,输出流用来向对方套接字输出数据。
3、利用输入输出流进行数据传输。
4、数据传输完毕后,关闭套接字连接。
看到这里可能有人会问,那么我想让客户机和客户及之间进行通信呢?我们可以利用服务器作为通信的中转站,比如客户机A要向客户机B发送数据,客户机A先将数据发送给服务器,服务器再将数据发送给客户机B。过程如图三所示
图三
三、如何用Java实现Socket编程
在Java语言里面,服务器端套接字使用ServerSocket类,客户端套接字使用Socket类。
在这之前先上一张图来总结套接字的通信流程。在看完流程图之后,想必大家会对套接字的通信流程有一个大致的了解,接下来我再详细讲解流程中使用到的方法。我觉得学习也是这么一个过程,从大致的框架再到对框架一点点地填充,这样才会对整个知识体系有一个清晰的认识。
图四
如图四所示
服务器端的程序步骤为:
(1)利用ServerSocket(port)方法,创建一个指定端口号的服务器,即一个ServerSocket类的对象,假设该对象为server.
(2)ServerSocket类对象server调用accept()方法侦听等待来自客户端的连接请求,若连接成功,返回一个Socket类对象用来通信,假设该对象为seversocket.
(3)通过socket调用getOutputStream(),和getOutputStream()得到输出流对象和输入流对象
(4)通过输入输出流对象,调用对应的read(),write()方法与客户端进行数据读写,完成与客户端的通信。
(5)当客户机端断开连接,关闭服务器,结束通信。
客户机端程序步骤为:
(1)利用Socket(IP,port)方法,建立一个客户机,即Socket类对象,假设该对象为clientsocket,该客户机自动请求与地址为IP,端口号为port的服务器连接。
(2)Socket类对象clientsocket调用getOutputStream(),和getOutputStream()得到输出流对象和输入流对象。
(3)通过输入输出流对象,调用对应的read(),write()方法与服务器端进行数据读写,完成与服务器的通信。
(4)通信完成之后,Socket类对象clientsocket调用close()方法关闭与服务器端的连接。
接下来对ServerSocket类和Socket类进行详细的介绍
1、ServerSocket类
服务器端使用ServerSocket类创建套接字。
网络通信中,ServerSocket类先创建一个套接字对象,等待客户机套接字的连接,一旦客户机套接字申请连接,服务器套接字对象则会通过accept()方法返回一个对应客户机套接字的服务器套接字。这个时候服务器和客户机之间才得到了真的连接,
1.1 ServerSocket类的构造方法
public ServerSocket(int port) throws IOException
功能:创建一个以port为端口号的服务器端socket套接字,当socket套接字连接数为50时,则拒绝其他客户机端套接字的连接
参数 port:端口号
public ServerSocket(int port,int backlog) throws IOException
功能:创建一个以port为端口号的服务器端socket套接字,当socket套接字连接数为 backlog时,则拒绝其他客户机端套接字的连接
参数 port:端口号
backlog:能连接的最大套接字数目。
1.2 ServerSocket类的普通方法
public IntAdress getInetAddress() //获取服务器端Socket的IP地址
public int getLocalPort() //获取服务器端Socket侦听的端口号
public Socket accept()throws IOException //服务器端指定端口号侦听客户端发出的连接请求,若接收到请求则与之连接,否则该方法一直阻塞知道连接成功。该方法返回一个新的Socket对象,服务器端通过它与连接的客户机端进行通信
public String toString()//返回该套接字的字符串表示
public void close()throws IOException//关闭Socket连接
2、Socket类
客户机端用socket类来创建套接字对象
2.1 Socket类的构造方法
public Socket(String host,int port)throws UnknowHostException,IOException
功能:创建一个指定服务器host和服务器端口号port套接字对象,并向服务器发送连接请求
参数:host:服务器主机名
port :服务器端口号
public Socket(InetAddress address,int port)throws IOException
功能:创建一个指定服务器ip地址和服务器端口号port套接字对象,并向服务器发送连接请求
参数:address:服务器ip地址
port :服务器端口号
2.2 与Socket数据读写有关的常用方法
public InputStream getInputStram()throws IOException
功能:为当前socket对象创建输入流
public OutPutStream getOutPutStream()throws IOException
功能:为当前socket对象创建输出流
以上两个方法非常重要,getInputStream()用来创建输入流对象,getOutputStream()用来创建输出流对象。有了输入输出流,程序就可以非常方便的进行读写。
2.3关闭socket连接的方法
public synchronized void close() throws IOEception
功能:关闭建立的socket连接。