基于TCP协议的网络编程:
TCP/IP通信协议是一种可靠的网络协议,他在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路。一旦建立了虚拟的网路链路,两端的程序就可以通过虚拟链路进行通信。Java对基于TCP协议的网络通信提供了良好的封装,Java使用socket对象来代表两端的通信接口,并通过socket产生的IO流来进行网络通信。
(1)通过使用IP协议,从而使Intenet成为一个允许连接不同类型计算机和不同操作系统的网络。
(2)IP协议只能保证计算机能发送和接受分组数据。IP协议负责将消息从一个主机传送到另一个主机,消息在传送过程中被分割成一个个的小包。
(3)Ip协议不能解决数据分组在传输过程中可能出现的问题。若要解决可能出现的问题,连上Internet的计算机还需要安装TCP协议来提供可靠且无差别的通信服务。
(4)TCP协议被称为一种端对端协议。这是因为它对两台计算机之间的连接起了重要作用–当一台计算机需要与另一台远程计算机相连时,TCP协议会让他们建立一个连接:用于发送和接受数据的虚拟链路。
(5)TCP协议保证了数据在传送中准确无误。TCP协议使用重发机制–当一个通信实体发送消息给另一个通信实体后,需要收到另一个通信实体的确认消息,如果没有收到另一个通信实体的确认消息,则会再次重发刚才发送的信息。
——————————————————————————————————————————————
使用ServerSocket创建TCP服务器端:
(1)Java中能接受其他通信实体连接请求的类是ServerSocket,ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接吧,它将一直处于连接状态。ServerSocket包含一个监听来自客户端连接请求的方法。
Socket accept() 如果接收到一个客户端Socket连接请求,该方法将返回一个与客户端的Socket对应的Socket;否则该方法将一直处于等待状态,线程也被阻塞。
(2)为了创建ServerSocket对象,ServerSocket类提供了如下几个构造器:
ServerSocket(int port) 用指定的端口port来创建一个ServerSocket。该端口应该有一个有效的端口整数值,即0–65535.
ServerSocket(int port, int backlog) 增加一个用来改变队列长度的backlog
ServerSocket(int port,int backlog,InetAddress localAddr) 在机器存在多个IP地址的情况下,允许通过localAddr参数来指定将ServerSocket绑定到指定的IP地址上。
(3)当ServerSocket使用完毕后,应使用ServerSocket的close()方法来关闭该ServerSocket。在通常情况下,服务器不应该只接受一个客户端请求,而应该不断接受来自客户端的请求,所以Java程序通常会通过循环不断地调用ServerSocket的accept()方法:
//创建一个ServerSocket,用于监听客户端Socket的连接请求
ServerSocket ss=new ServerSocket(30000); //通常推荐使用1024以上的端口
//采用循环不断地接受来自客户端的请求
while(true){
//每当接收到客户端的Socket请求时,服务器端也会对应产生一个Socket
Socket s=ss.accept();
//下面就可以使用Socket进行通信了
}
————————————————————————————————
使用Socket进行通信:
(1)客户端通常可以使用Socket的构造器来连接到指定服务器,Socket通常有如下两个构造器:
Socket(InetAddress/String remoteAddress ,int port) 创建连接到远程主机,远程端口的Socket,该构造器没有指定本地地址,本地端口,默认使用本机的默认IP地址,默认使用系统动态分配的端口。
Socket(InetAddress/String remoteAddress ,int port,InetAddress localAddr,int localPort) 创建连接到远程主机,远程端口的Socket,并指定本机地址和本机端口,适用于本地主机有多个IP地址的情形。
程序通常使用String 对象(如192.168.2.3)来指定远程IP地址。当本地主机只有一个IP地址时,使用第一个方法更简单,如:
//创建连接到本机,30000端口的Socket
Socket s =new Socket(“127.0.0.1”,30000);
//下面就可以使用Socket进行通信了
当程序执行上面代码时,该代码会连接到指定服务器端,让服务器端的SecverSocket的accept()方法向下执行,于是服务器端和客户端就产生了一对互相连接的Socket。
(2)当服务器端、客户端产生了对应的Socket后,程序无须再区分服务器端和客户端,而是通过各自的Socket进行通信。Socket提供了如下两个方法来获取输入流和输出流:
InputStream getInputStream() 返回该Socket对象对应的输入流,让程序通过该输入流从Socket取出数据。
OutputStream getOutputStream() 返回该Socket对象对应的输出流,让程序通过该输出流从Socket输出数据。
程序实例:简单的网络通信程序:
服务器端:建立Server监听,并使用Socket获取输入输出流:
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//创建一个ServerSocket,用于监听客户端Socket的连接请求
ServerSocket ss=new ServerSocket(30000);
//采用循环不断接受来自客户端的请求
while(true){
//每当接收到客户端Socket的请求时,服务器端也对应产生一个Socket
Socket s =ss.accept();
//将Socket对应的输出流包装成PrintStream
PrintStream ps=new PrintStream(s.getOutputStream());
ps.println("您好,服务器端收到了");
//关闭输出流,关闭Socket
ps.close();
s.close();
}
}
}
客户端:使用Socket建立与指定IP地址、指定端口的连接,并使用Socket获取输入流读取数据。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws IOException{
Socket socket=new Socket("127.0.0.1", 30000);
//将Socket对应的输入流包装成对应的BufferedReader
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//进行普通IO操作
String line =br.readLine();
System.out.println("来自服务器的数据:"+line);
//关闭输出流,关闭Socket
br.close();
socket.close();
}
}
(3)在实际应用中,程序可能不想让直行网络连接、读取服务器数据进程一直阻塞,而是希望当前网络连接、读取操作超过合理时间以后,系统自动认为该操作失败,这个合理时间就是超时时长。Socket对象提供了一个setSoTimeout(int timeout)方法来设置超时时长。
Socket s=new Socket(“127.0.0.1” ,30000);
//设置10秒后认为超时
s.setSoTimeout(10000);