所谓socket 通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过”套接字”向网络发出请求或者应答网络请求。

InetAddress

InetAddress可以获取对应ip或者对应域名的相关信息,例如ip信息和域名信息

只说一下用的比较多的吧

获取InetAddress对象,只能使用工厂构造方法获取。

1
2
3
4
5
6
7
//获取本地主机的相关信息。
InetAddress localHost = InetAddress.getLocalHost();
InetAddress localhost = InetAddress.getByName("localhost");
//获取主机名为 DESKTOP-GQI06FR 的相关信息
InetAddress inetAddress = InetAddress.getByName("DESKTOP-GQI06FR");
//获取网站相关信息
InetAddress inetAddress = InetAddress.getByName("www.baidu.com");

InetAddress对象的使用,常用方法

1
2
3
4
//ip
String hostAddress = localHost.getHostAddress();//获取IP地址
//主机名称
String hostName = localHost.getHostName();//获取主机名称 或者 域名

TCP客户端

以发送简单的字符串为例。

TCP发送数据的步骤

  1. 创建客户端的Socket对象(Socket)
  2. 获取输出流,写数据
  3. 释放资源

首先创建Socket对象

1
Socket socket = new Socket("127.0.0.1",50000);

常用的构造方法有两个:

  • Socket (InetAddress address, int port)创建流套接字并将其连接到指定IP地址的指定端口号
  • Socket (String host, int port)创建流套接字并将其连接到指定主机上的指定端口号

获取字节输出流

你可以使用普通的输出流

1
OutputStream outputStream = socket.getOutputStream();

你还可以使用字符缓存流

1
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

还可以使用字节缓存流

1
BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());

获取字节输入流

获取输入流可以获取反馈信息

1
InputStream clientInputStream = socket.getInputStream();

字符缓存流和字节缓冲流和上面的类似。

写数据

1
2
3
4
Scanner sc = new Scanner(System.in);
String next = sc.next();
//使用 普通的输出流
stream.write(next.getBytes());

释放资源

1
2
stream.close();
socket.close();

TCP服务端

创建服务器端的socket对象(ServerSocket)

ServerSocket (int port)创建绑定到指定端口的服务器套接字

1
ServerSocket server = new ServerSocket(9000);

Socket accept()侦听要连接到此套接字并接受它

1
Socket accept = server.accept();

accept() 阻塞式监听,会一直等待客户端连接

获取字节输入流和字节输出流

1
2
InputStream stream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();

接收数据

1
2
3
4
5
6
byte[] buffer = new byte[1024];
int len;
while ((len = stream.read(buffer))!=-1){
String msg = new String(buffer, 0, len);
System.out.println(msg);
}

这样写的缺点是,假如有中文,超过了1024,然后就断掉了。断掉之后就乱码了。

管道流

1
2
3
4
5
6
7
byte[] buffer = new byte[1024];
int len;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = stream.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());

关闭资源

1
2
3
4
accept.close();
stream.close();
outputStream.close();
server.close();

案例

客户端发送消息字符串,服务端接收消息字符串。客户端输入“exit”结束发送,服务端发送“接收完毕”反馈,客户端接收反馈。

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost",10001);

OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

Scanner sc = new Scanner(System.in);
String text;
while (!(text=sc.next()).equals("exit")){
bw.write(text);
bw.newLine();
bw.flush();
}

socket.shutdownOutput();//不使用的话,服务端就会发送阻塞,不会发送反馈,客户端也就会发送阻塞。

System.out.println("END");
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
System.out.println(line);

socket.close();
bw.close();
}
}

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10001);

Socket accept = serverSocket.accept();

InputStream inputStream = accept.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String text;
while ((text = reader.readLine())!=null){
System.out.println(text);
}
OutputStream outputStream = accept.getOutputStream();
outputStream.write("接收完毕!".getBytes());

System.out.println("END");
accept.close();
serverSocket.close();
}
}

关于shutdownOutput()的作用:

socket.shutdownOutput():关闭客户端的输出流。相当于给流中加入一个结束标志-1,这个时候服务器端的输入流的readLine()相当于读到了一个-1【null】,所以,就会结束while ((text = reader.readLine())!=null)循环,接着往下执行。

image-20220816205526066

IO流相关操作,参考我另一篇博客——Java-IO流

__END__