【有书共读】《疯狂JAVA讲义》读书笔记17
Socket 编程
套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:
-
服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
-
服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
-
服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
-
Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
-
在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket
客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。
服务器端
public class SocketServer {
public static void main(String[] args) throws IOException {
// 端口号
int port = 7000;
// 在端口上创建一个服务器套接字
ServerSocket serverSocket = new ServerSocket(port);
// 监听来自客户端的连接
Socket socket = serverSocket.accept();
DataInputStream dis = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(socket.getOutputStream()));
do {
double length = dis.readDouble();
System.out.println("服务器端收到的边长数据为:" + length);
double result = length * length;
dos.writeDouble(result);
dos.flush();
} while (dis.readInt() != 0);
socket.close();
serverSocket.close();
}
}
客户端
public class SocketClient {
public static void main(String[] args) throws UnknownHostException, IOException {
int port = 7000;
String host = "localhost";
// 创建一个套接字并将其连接到指定端口号
Socket socket = new Socket(host, port);
DataInputStream dis = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(socket.getOutputStream()));
Scanner sc = new Scanner(System.in);
boolean flag = false;
while (!flag) {
System.out.println("请输入正方形的边长:");
double length = sc.nextDouble();
dos.writeDouble(length);
dos.flush();
double area = dis.readDouble();
System.out.println("服务器返回的计算面积为:" + area);
while (true) {
System.out.println("继续计算?(Y/N)");
String str = sc.next();
if (str.equalsIgnoreCase("N")) {
dos.writeInt(0);
dos.flush();
flag = true;
break;
} else if (str.equalsIgnoreCase("Y")) {
dos.writeInt(1);
dos.flush();
break;
}
}
}
socket.close();
}
}
A类:10.0.0.0~10.255.255.255;
B类:172.16.0.0~172.31.255.255;
C类:192.168.0.0~192.168.255.255
公认端口:0~1023;
注册端口:1024~49151,应用程序通常使用这些端口;
动态和/或私有端口:49152~65535,应用程序一般不会主动使用这些端口。
使用InetAddress:InetAddress没有提供构造器,而是提供两个静态方法来获取InetAddress实例:①getByName(String host):根据主机获取对应的InetAddress对象;②getByAddress(byte[] addr):根据原始IP地址获取对应的InetAddress对象。InetAddress还提供了3个方法来获取InetAddress实例对应的IP地址和主机名:①String getCanoicalHostName():获取此IP地址的全限定域名;②String getHostAddress():返回此InetAddress实例对应的IP地址和字符串;③String getHostName():获取此IP地址的主机名。InetAddress还提供了一个getLocalHost()方法来获取本机IP地址和InetAddress实例。InetAddress还提供了isReachable()方法来测试是否可以到达该地址。
InetAddress ip=InetAddress.getByName("www.crazyit.org");
System.out.println("是否可以到达某网站:"+ip.isReachable(2000));
System.out.println(ip.getHostAddress());
InetAddress local=InetAddress.getByAddress(new byte[] {127,0,0,1});
System.out.println("本机是否可达:"+local.isReachable(2000));
System.out.println(local.getCanonicalHostName());
输出:是否可以到达某网站:true 222.73.85.205 本机是否可达:true 127.0.0.1
使用ServerSocket创建TCP服务端:ServerSocket对象用于监听来自客户端的Socket请求,如果没有连接,将一直处于等待状态:①Socket accept():如果接收到一个客户端Socket请求,将返回一个与客户端Socket对应的Socket。ServerSocket提供了如下几个构造器:①Socket accept(int port):用指定端口port来创建一个ServerSocket,有效值0-65535。当ServerSocket使用完毕后,应使用close方法来关闭该ServerSocket。
IP地址是:127.0.0.1一般代表本机的IP地址。Socket提供了2个方法来获取输入流和输出流:InputStream getInputStream和OutputStream getOutputStream。Socket对象提供了一个setSoTimeout(int millis)的超时连接。
Socket通信例子
客户端:Socket conToServer=new Socket("localhost",5500);
//数据输入流:
DataInputStream inFromSer=new DataInputStream(conToServer.getInputStream());
//数据输出流:
DataOutputStream outToSer=new DataOutputStream(conToServer.getOutputStream());
服务端:ServerSocket serSock=new ServerSocket(5500);
//侦听来自客户端的连接请求
Socket conFromCli=serSock.accept();
//接收数据:
DataInputStream inFromCli=new DataInputStream(conFromCli.getInputStream());
使用DatagramSocket发送、接收数据:DatagramSocket构造器有3个:①DatagramSocket()无参数构造器表示绑定到本机默认IP地址、本机的所有可以用的随机端口;②DatagramSocket(int port)③DatagramSocket(int port,InetAddress add),都很好理解。通过如下两个方法来接收和发送数据:receive(DatagramSocket p); send(DatagramSocket p)。
使用***服务器:
***服务器的功能就是***用户去取得网络信息,浏览器不是直接去向Web服务器发送请求,而是向***服务器发送请求。***服务器有2个好处:①突破自身IP限制,对外隐藏自身IP地址,包括访问国外受限站点,访问国内特定单位、团体的内部资源;②提高访问速度,***服务器提供缓存功能可以避免用户直接访问远程主机,从而提高客户端的访问速度。