本系列文章主要为了学习socket和httpUrlConnection的使用,涉及到的知识范围比较广泛,所以记录一下。
本篇实现的功能为通过socket编写服务端,使用Telnet模拟客户端发送消息给服务端,并将消息+当前时间显示在控制台。
(1)首先要了解一下socket是什么。
Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的API(应用程序编程接口),也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 Socket中,该 Socket通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 Socket中,使对方能够接收到这段信息。 Socket是由IP地址和端口结合的,提供向应用层进程传送数据包的机制。
——以上摘自百度。
简单来说,socket提供了这样一种功能:如果有A、B两个端口想要通信,socket会在两者中建立起连接,并给每人一个socket文件,用来记录对方写入的消息。比如A想给B发消息,就将消息写入B的文件中,B就能够通过读取文件来知道A给他发了什么信息,反之,B也可以给A发消息。
所以通过socket进行通信,主要的步骤就是:建立连接,写入,读取。
(2)还要了解一下Telnet
Telnet协议是TCP/IP协议族中的一员,是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法。
——以上摘自百度。
Telnet能够通过ip地址和端口号进行访问,在本篇文章实现的功能中,只充当一个客户端,用于测试服务端的代码功能。
通常情况下,系统默认不开启Telnet服务,所以如果要使用Telnet模拟需要先开启Telnet服务。
如何打开Telnet服务以及测试连接
打开服务: windows11系统下,选择控制面板 -> 程序 -> 程序和功能下的启用或关闭Windows功能,选择Telnet客户端,点击确定后,等待一会即可打开Telnet服务。
测试:win+R打开运行窗口,输入cmd敲回车,进入后台。输入已经打开的本地ip和端口号(一般135端口都是打开的),进入黑色窗口(如图1),即连接成功。
C:\Users>telnet localhost 135
图1 Telnet localhost 135 连接成功
如果连接的端口没有打开,则如下显示。
C:\Users>telnet localhost 123
正在连接localhost...无法打开到主机的连接。 在端口 123: 连接失败
如果碰巧135端口没开,又不知道有哪个端口是打开的,可以输入代码 netstat -na 查一下。右侧状态显示为listening的端口,就是已经打开可以用于测试的端口。
netstat -na
图2 监听的端口
之前查看的教程中提及,如果想要连接别人的电脑,需要被连接的电脑开启Telnet服务端,但在windows11系统中,只找到了客户端,并其在只打开客户端的情况下,确实无法连接其他人电脑,猜测可能是系统版本问题。
(3)服务端
用于测试的客户端准备就绪,接下来就开始处理服务端了。如上文所说,需要建立连接和对文件写入和读出。
public class TelServerV2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ServerSocket ss = new ServerSocket(8888);
System.out.println("已开启端口8888服务");
//date format utils
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true){
Socket s = ss.accept();
System.out.printf("got client connection: %s%n", s.getRemoteSocketAddress());
// get the reader
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
//get the output stream
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while((line = reader.readLine()) !=null){
System.out.printf("get message from client: %s%n", line);
// response back to client
String now = sdf.format(new Date());
pw.println(String.format("%s - %s", now, line));
pw.flush();
}
}catch (Exception ex){
System.out.printf("got error: %s%n", ex.getMessage());
ex.printStackTrace();
}finally {
//we should close it anyway
System.out.printf("close client %s%n", s.getRemoteSocketAddress());
ss.close();
}
}
}
}
(后续将补充关于文件的输入输出流相关。)
(4)使用Telnet测试
先运行服务端代码,启动端口。再在刚才Telnet测试的后台输入telnet localhost 8888(如果使用了其他端口就更换为其他端口号,localhost和127.0.0.1的效果相同)。
敲下回车后显示连接成功的黑窗口,输入要发送的信息,但第一行输入在黑窗口是看不到的,发送后,可以在服务端控制台看到。之后输入的都可以看到。此外,如果输入错了,Telnet的黑窗口返回的可能会出错,但在控制台显示的是对的。由于本篇只考虑了通信功能,所以没有详细深究此问题。
C:\Users>telnet localhost 8888
图3 Telnet黑窗口
图4 服务端控制台
本篇实现了通过Telnet发送消息给服务端的功能,但只能实现一对一的连接,后续将多对一的连接,即多个客户端一个服务端。实现该功能,需要使用多线程对每个对话建立一个连接,将在之后与文件的读写一起更新。