网络编程【TCP单向通信、TCP双向通信、一对多应用、一对多聊天服务器】(二)-全面详解(学习总结---从入门到深化)

 

 

目录

Java网络编程中的常用类

TCP通信的实现和项目案例

TCP通信入门案例 

TCP单向通信

TCP双向通信

创建点对点的聊天应用

一对多应用

一对多聊天服务器


Java网络编程中的常用类

Java为了跨平台,在网络应用通信时是不允许直接调用操作系统接 口的,而是由java.net包来提供网络功能。下面我们来介绍几个 java.net包中的常用的类。

InetAddress的使用 

作用:封装计算机的IP地址和DNS(没有端口信息)

注:DNS是Domain Name System,域名系统。

特点:

这个类没有构造方法。如果要得到对象,只能通过静态方法:

getLocalHost()、getByName()、 getAllByName()、 getAddress()、getHostName()

 获取本机信息

获取本机信息需要使用getLocalHost方法创建InetAddress对象。 getLocalHost()方法返回一个InetAddress对象,这个对象包含了本 机的IP地址,计算机名等信息。

public class InetTest {public static void main(String[] args)throws Exception {//实例化InetAddress对象InetAddress inetAddress = InetAddress.getLocalHost();//返回当前计算机的IP地址System.out.println(inetAddress.getHostAddress());//返回当前计算机名System.out.println(inetAddress.getHostName());}
}

根据域名获取计算机的信息

根据域名获取计算机信息时需要使用getByName(“域名”)方法创建 InetAddress对象。

public class InetTest2 {public static void main(String[] args)throws Exception {InetAddress inetAddress = InetAddress.getByName("www.baidu.com");System.out.println(inetAddress.getHostAddress());System.out.println(inetAddress.getHostName());}
}

根据IP获取计算机的信息

根据IP地址获取计算机信息时需要使用getByName(“IP”)方法创建 InetAddress对象。

public class InetTest3 {public static void main(String[] args)throws  Exception {InetAddress inetAddress = InetAddress.getByName("14.215.177.38");System.out.println(inetAddress.getHostAddress());System.out.println(inetAddress.getHostName());}
}

 InetSocketAddress的使用

作用:包含IP和端口信息,常用于Socket通信。此类实现 IP 套接字 地址(IP 地址 + 端口号),不依赖任何协议。 InetSocketAddress相比较InetAddress多了一个端口号,端口的作 用:一台拥有IP地址的主机可以提供许多服务,比如Web服务、 FTP服务、SMTP服务等,这些服务完全可以通过1个IP地址来实 现。 那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址, 因为IP 地址与网络服务的关系是一对多的关系。实际上是通过“IP地 址+端口号”来区分不同的服务的。

public class InetSocketTest {public static void main(String[] args) {InetSocketAddress inetSocketAddress = new InetSocketAddress("www.baidu.com",80);System.out.println(inetSocketAddress.getAddress().getHostAddress());System.out.println(inetSocketAddress.getHostName());}
}

URL的使用

IP地址标识了Internet上唯一的计算机,而URL则标识了这些计算机 上的资源。 URL 代表一个统一资源定位符,它是指向互联网“资源” 的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对 象的引用,例如对数据库或搜索引擎的查询。 为了方便程序员编程,JDK中提供了URL类,该类的全名是 java.net.URL,有了这样一个类,就可以使用它的各种方法来对 URL对象进行分割、合并等处理。

public class UrlTest {public static void main(String[] args)throws Exception {URL url = new URL("https://www.itbaizhan.com/search.html?kw=java");System.out.println("获取与此URL相关联协议的默认端口:"+url.getDefaultPort());System.out.println("访问资源:"+url.getFile());System.out.println("主机名"+url.getHost());System.out.println("访问资源路径:"+url.getPath());System.out.println("协议:"+url.getProtocol());System.out.println("参数部分:"+url.getQuery());}
}

 通过URL实现最简单的网络爬虫

public class UrlTest2{public static void main(String[] args)throws Exception {URL url = new URL("https://www.itbaizhan.com/");try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {StringBuilder sb = new StringBuilder();String temp;/** 这样就可以将网络内容下载到本地机器。* 然后进行数据分析,建立索引。这也是搜索引擎的第一步。*/while ((temp = br.readLine()) != null) {sb.append(temp);}System.out.println(sb);} catch (Exception e) {e.printStackTrace();}}
}

TCP通信的实现和项目案例

TCP通信实现原理

前边我们提到TCP协议是面向的连接的,在通信时客户端与服务器 端必须建立连接。在网络通讯中,第一次主动发起通讯的程序被称 作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的 程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则 客户端和服务器端完全一样,没有本质的区别。

 “请求-响应”模式:

Socket类:发送TCP消息。

ServerSocket类:创建服务器。

 套接字Socket是一种进程间的数据交换机制。这些进程既可以在同 一机器上,也可以在通过网络连接的不同机器上。换句话说,套接 字起到通信端点的作用。单个套接字是一个端点,而一对套接字则 构成一个双向通信信道,使非关联进程可以在本地或通过网络进行 数据交换。一旦建立套接字连接,数据即可在相同或不同的系统中 双向或单向发送,直到其中一个端点关闭连接。套接字与主机地址 和端口地址相关联。主机地址就是客户端或服务器程序所在的主机 的IP地址。端口地址是指客户端或服务器程序使用的主机的通信端 口。 在客户端和服务器中,分别创建独立的Socket,并通过Socket的属 性,将两个Socket进行连接,这样,客户端和服务器通过套接字所 建立的连接使用输入输出流进行通信。 TCP/IP套接字是最可靠的双向流协议,使用TCP/IP可以发送任意数 量的数据。 实际上,套接字只是计算机上已编号的端口。如果发送方和接收方 计算机确定好端口,他们就可以通信了。 客户端与服务器端的通信关系图:

 

 TCP/IP通信连接的简单过程:

位于A计算机上的TCP/IP软件向B计算机发送包含端口号的消息,B 计算机的TCP/IP软件接收该消息,并进行检查,查看是否有它知道 的程序正在该端口上接收消息。如果有,他就将该消息交给这个程 序。 要使程序有效地运行,就必须有一个客户端和一个服务器。

 通过Socket的编程顺序:

1 创建服务器ServerSocket,在创建时,定义ServerSocket的监听端口(在这个端口接收客户端发来 的消息)

2 ServerSocket调用accept()方法,使之处于阻塞状态。

3 创建客户端Socket,并设置服务器的IP及端口。

4 客户端发出连接请求,建立连接。

5 分别取得服务器和客户端Socket的InputStream和OutputStream。

6 利用Socket和ServerSocket进行数据传输。

7 关闭流及Socket。

TCP通信入门案例 

创建服务端

public class BasicSocketServer {public static void main(String[] args) {System.out.println("服务器启动等待监听。。。。");//创建ServerSockettry(ServerSocket ss =new ServerSocket(8888);//监听8888端口,此时线程会处于阻塞状态。Socket socket = ss.accept();//连接成功后会得到与客户端对应的 Socket对象,并解除线程阻塞。//通过客户端对应的Socket对象中的输入流对象,获取客户端发送过来的消息。BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()))){       System.out.println(br.readLine());}catch(Exception e){e.printStackTrace();System.out.println("服务器启动失败。。。。");}}
}

创建客户端

public class BasicSocketClient {public static void main(String[] args) {//创建Socket对象try(Socket socket =new Socket("127.0.01",8888);//创建向服务端发送消息的输出流对象。PrintWriter pw = new PrintWriter(socket.getOutputStream())){pw.println("服务端,您好!");pw.flush();}catch(Exception e){e.printStackTrace();}}
}

TCP单向通信

单向通信是指通信双方中,一方固定为发送端,一方则固定为接收 端。

 创建服务端

public class OneWaySocketServer {public static void main(String[] args) {System.out.println("服务端启动,开始监听。。。。。");try(ServerSocket serverSocket = new ServerSocket(8888);//监听8888端口,获与取客户端对应的 Socket对象Socket socket = serverSocket.accept();//通过与客户端对应的Socket对象获取输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//通过与客户端对应的Socket对象获取输出流对象PrintWriter pw = new PrintWriter(socket.getOutputStream())){System.out.println("连接成功!");while(true){//读取客户端发送的消息String str = br.readLine();System.out.println("客户端说:"+str);if("exit".equals(str)){break;}pw.println(str);pw.flush();}}catch(Exception e){e.printStackTrace();System.out.println("服务端启动失败。。。。。");}}
}

创建客户端

public class OneWaySocketClient {public static void main(String[] args) {//获取与服务端对应的Socket对象try(Socket socket = new Socket("127.0.0.1",8888);//创建键盘输入对象Scanner scanner = new Scanner(System.in);//通过与服务端对应的Socket对象获取输出流对象PrintWriter pw = new PrintWriter(socket.getOutputStream());//通过与服务端对应的Socket对象获取输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()))){while(true){//通过键盘输入获取需要向服务端发送的消息String str = scanner.nextLine();//将消息发送到服务端pw.println(str);pw.flush();if("exit".equals(str)){break;}//读取服务端返回的消息String serverInput = br.readLine();System.out.println("服务端返回的:"+serverInput);}}catch(Exception e){e.printStackTrace();}}
}

TCP双向通信

双向通信是指通信双方中,任何一方都可为发送端,任何一方都可 为接收端。

创建服务端

public class TwoWaySocketServer {public static void main(String[] args) {System.out.println("服务端启动!监听端口8888。。。。");try(ServerSocket serverSocket  = new ServerSocket(8888);Socket socket = serverSocket.accept();//创建键盘输入对象Scanner scanner = new Scanner(System.in);//通过与客户端对应的Socket对象获取输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//通过与客户单对应的Socket对象获取输出流对象PrintWriter pw  = new PrintWriter(socket.getOutputStream());){while(true){//读取客户端发送的消息String str = br.readLine();System.out.println("客户端说:"+str);String keyInput = scanner.nextLine();//发送到客户端pw.println(keyInput);pw.flush();}}catch(Exception e){e.printStackTrace();}}
}

创建客户端

public class TwoWaySocketClient {public static void main(String[] args) {try(Socket socket = new Socket("127.0.0.1", 8888);//创建键盘输入对象Scanner  scanner = new Scanner(System.in);//通过与服务端对应的Socket对象获取输入流对象BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//通过与服务端对应的Socket对象获取输出流对象PrintWriter pw = new PrintWriter(socket.getOutputStream());){while (true) {String keyInput = scanner.nextLine();pw.println(keyInput);pw.flush();String input = br.readLine();System.out.println("服务端说:" + input);}} catch (Exception e) {e.printStackTrace();}}
}

创建点对点的聊天应用

创建服务端

/**
* 发送消息线程
*/
class Send extends Thread{private Socket socket;public Send(Socket socket){this.socket = socket;}@Overridepublic void run() {this.sendMsg();}/*** 发送消息*/private void sendMsg(){//创建Scanner对象try(Scanner scanner = new Scanner(System.in);//创建向对方输出消息的流对象PrintWriter pw = new PrintWriter(this.socket.getOutputStream());){while(true){String msg = scanner.nextLine();pw.println(msg);pw.flush();}}catch(Exception e){e.printStackTrace();}}
}
/**
* 接收消息的线程
*/
class Receive extends Thread{private Socket socket;public Receive(Socket socket){this.socket = socket;}@Overridepublic void run() {this.receiveMsg();}/*** 用于接收对方消息的方法*/private void receiveMsg(){//创建用于接收对方发送消息的流对象try(BufferedReader  br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));){while(true){String msg = br.readLine();System.out.println("他说:"+msg);}}catch(Exception e){e.printStackTrace();}}
}
public class ChatSocketServer {public static void main(String[] args) {try(ServerSocket serverSocket = new ServerSocket(8888);){System.out.println("服务端启动,等待连接。。。。。");Socket socket = serverSocket.accept();System.out.println("连接成功!");new Send(socket).start();new Receive(socket).start();}catch(Exception e){e.printStackTrace();}}
}

创建客户端

/**
* 用于发送消息的线程类
*/
class ClientSend extends Thread{private Socket socket;public ClientSend(Socket socket){this.socket = socket;}@Overridepublic void run() {this.sendMsg();}/*** 发送消息*/private void sendMsg(){//创建Scanner对象try(Scanner scanner = new Scanner(System.in);//创建向对方输出消息的流对象PrintWriter pw = new PrintWriter(this.socket.getOutputStream());){while(true){String msg = scanner.nextLine();pw.println(msg);pw.flush();}}catch(Exception e){e.printStackTrace();}}
}
/**
* 用于接收消息的线程类
*/
class ClientReceive extends Thread{private Socket socket;public ClientReceive(Socket socket){this.socket = socket;}@Overridepublic void run() {this.receiveMsg();}/*** 用于接收对方消息的方法*/private void receiveMsg(){//创建用于接收对方发送消息的流对象try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));){while(true){String msg = br.readLine();System.out.println("他说:"+msg);}}catch(Exception e){e.printStackTrace();}}
}
public class ChatSocketClient {public static void main(String[] args) {try {Socket socket = new Socket("127.0.0.1", 8888);System.out.println("连接成功!");new ClientSend(socket).start();new ClientReceive(socket).start();}catch(Exception e){e.printStackTrace();}}
}

优化点对点聊天应用

/**
* 发送消息线程
*/
class Send extends Thread{private Socket socket;private Scanner scanner;public Send(Socket socket,Scanner scanner){this.socket = socket;this.scanner = scanner;
}@Overridepublic void run() {this.sendMsg();}/*** 发送消息*/private void sendMsg(){//创建向对方输出消息的流对象try(PrintWriter pw = new PrintWriter(this.socket.getOutputStream()))
{while(true){String msg = scanner.nextLine();pw.println(msg);pw.flush();}}catch(Exception e){e.printStackTrace();}}
}
/**
* 接收消息的线程
*/
class Receive extends Thread{private Socket socket;public Receive(Socket socket){this.socket = socket;}@Overridepublic void run() {this.receiveMsg();}/*** 用于接收对方消息的方法*/private void receiveMsg(){//创建用于接收对方发送消息的流对象try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()))){while(true){String msg = br.readLine();System.out.println("他说:"+msg);}}catch(Exception e){e.printStackTrace();}}
}
public class GoodTCP {public static void main(String[] args){Scanner scanner = null;ServerSocket serverSocket = null;Socket socket = null;try{scanner = new Scanner(System.in);System.out.println("请输入:server,<port> 或者:<ip>,<port>");String str = scanner.nextLine();String[] arr = str.split(",");if("server".equals(arr[0])){//启动服务端System.out.println("TCP Server Listen at "+arr[1]+" .....");serverSocket = new ServerSocket(Integer.parseInt(arr[1]));socket = serverSocket.accept();System.out.println("连接成功!");}else{//启动客户端socket = new Socket(arr[0],Integer.parseInt(arr[1]));System.out.println("连接成功!");}//启动发送消息的线程new Send(socket,scanner).start();//启动接收消息的线程}catch(Exception e){e.printStackTrace();}finally{if(serverSocket != null){try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

一对多应用

一对多应用设计

各socket对间独立问答,互相间不需要传递信息。

 一对多应答型服务器

/**
* 定义消息处理线程类
*/
class Msg extends Thread{private Socket socket;public Msg(Socket socket){this.socket = socket;}@Overridepublic void run() {this.msg();}/*** 将从客户端读取到的消息写回给客户端*/private void msg(){try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));PrintWriter pw = new PrintWriter(this.socket.getOutputStream())){while(true){pw.println(br.readLine()+" [ok]");pw.flush();}}catch(Exception e){e.printStackTrace();System.out.println(this.socket.getInetAddress()+" 断线了!");}}
}
public class EchoServer {public static void main(String[] args) {try(ServerSocket serverSocket = new ServerSocket(8888)){//等待多客户端连接while(true){Socket socket = serverSocket.accept();new Msg(socket).start();}}catch(Exception e){e.printStackTrace();}}
}

一对多聊天服务器

服务器设计

1、服务器的连接设计

2、服务器的线程设计

 创建一对多聊天服务应用

/**
* 接收客户端消息的线程类
*/
class ChatReceive extends Thread{private Socket socket;public ChatReceive(Socket socket){this.socket =socket;}@Overridepublic void run() {this.receiveMsg();}/*** 实现接收客户端发送的消息*/private void receiveMsg(){try(BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()))){while(true){String msg = br.readLine();synchronized ("abc"){//把读取到的数据写入公共数据区ChatRoomServer.buf=" ["+this.socket.getInetAddress()+"] "+msg;//唤醒发送消息的线程对象。"abc".notifyAll();}}}catch(Exception e){e.printStackTrace();}}
}
/**
* 向客户端发送消息的线程类
*/
class ChatSend extends Thread{private Socket socket;public ChatSend(Socket socket){this.socket = socket;}@Overridepublic void run() {this.sendMsg();}/*** 将公共数据区的消息发送给客户端*/private void sendMsg(){try(PrintWriter  pw = new PrintWriter(this.socket.getOutputStream())){while(true){synchronized ("abc"){//让发送消息的线程处于等待状态"abc".wait();//将公共数据区中的消息发送给客户端pw.println(ChatRoomServer.buf);pw.flush();}}}catch(Exception e){e.printStackTrace();}}
}
public class ChatRoomServer {//定义公共数据区public static String buf;public static void main(String[] args) {System.out.println("Chat Server Version 1.0");System.out.println("Listen at 8888.....");try(ServerSocket serverSocket = new ServerSocket(8888)){while(true){Socket socket = serverSocket.accept();System.out.println("连接到:"+socket.getInetAddress());new ChatReceive(socket).start();new ChatSend(socket).start();}}catch(Exception e){e.printStackTrace();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/17966.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ARIMA-SSA-LSTM】合差分自回归移动平均方法-麻雀优化-长短期记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

允许Traceroute探测漏洞和ICMP timestamp请求响应漏洞解决方法(三)

目录 服务器检测出了漏洞需要修改 1.允许Traceroute探测漏洞解决方法 2、ICMP timestamp请求响应漏洞 服务器检测出了漏洞需要修改 1.允许Traceroute探测漏洞解决方法 详细描述 本插件使用Traceroute探测来获取扫描器与远程主机之间的路由信息。攻击者也可以利用这些信息来…

word自动编号变黑块的亲测解决方案

具体问题如下&#xff1a; 出现这种情况就是word的自动编号字体出错&#xff0c;可以在word中运行脚本来解决&#xff1a; Sub repair()For Each templ In ActiveDocument.ListTemplates For Each lev In templ.ListLevels lev.Font.Reset Next lev Next templEnd Sub代码如上…

信息安全-应用安全-软件成分安全分析(SCA)能力的建设与演进

1. 前言 SCA 概念出现其实很久了。简单来说&#xff0c;就是针对现有的软件系统生成粒度非常细的 SBOM&#xff08;Software Bill of Materials 软件物料单&#xff09;清单&#xff0c;然后通过⻛险数据去匹配有没有存在⻛险组件被引用。目前&#xff0c;市面上比较出色的商业…

Spring Cloud的基本应用

上篇文章我们的eureka的集群已经搭建完毕,但是我们还没有开始使用,之前我们的page访问的方法是直接写死的,现在我们就可以改为集群的方式来写 Autowired//注册中心对应的客户端对象private DiscoveryClient discoveryClient;RequestMapping("query/{id}")public Prod…

[MMDetection]测试模型

以下是基于MMdetection3.10版本 1、简单测试模型 测试模型一般使用tools中的test.py&#xff0c;一般使用方式 python tools/test.py config文件路径 权重文件路径 可以通过--show 来以gui展示检测结果 python tools/test.py config文件路径 权重文件路径 --show 可以通过--s…

Jstat命令解析

Jstat命令解析 Jstat是JDK自带的一个轻量级小工具。全称“Java Virtual Machine statistics monitoring tool”&#xff0c;它位于java的bin目录下&#xff0c;主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控&#xff0c;包括了对Heap size和垃圾回收…

数据库之MySQL字符集与数据库操作

目录 字符集 CHRARCTER SET 与COLLATION的关联 CHRARCTER SET 定义 基础操作 查看当前MySQL Server支持的 CHARACTER SET 查看特定字符集信息&#xff08;主要包含默认的COLLATION 与 MAXLEN&#xff09; COLLATION 定义 COLLATION后缀 基础操作 查看MySQL Server支持的…

ChatGPT助力校招----面试问题分享(十一)

1 ChatGPT每日一题&#xff1a;PCB布线&#xff0c;高速信号线走直角的后果 问题&#xff1a;PCB布线&#xff0c;高速信号线走直角的后果 ChatGPT&#xff1a;对于高速信号线来说&#xff0c;最好避免使用直角布线。直角布线会引入反射和信号损耗&#xff0c;从而导致信号完…

如何监测电路中恶性负载

随着社会的发展和科技的进步&#xff0c;人们对于用电的安全性和稳定性要求越来越高。电路中的恶性负载往往会导致电路故障&#xff0c;甚至引发火灾等严重事故。因此&#xff0c;如何监测电路中的恶性负载成为了一个重要的课题。本文将从恶性负载的定义、监测方法、防范措施等…

Qt窗体全屏与复原,子窗体全屏与复原

QT QWidget窗体全屏时&#xff0c;全屏与最大化的区别时最大化有标题框全屏没有框&#xff0c;可以使用自带的函数&#xff1a; showFullScreen(); 复原时也有专门的函数&#xff1a; showNormal(); 如果我想在点击最大化按钮时&#xff0c;让窗体全屏。这个时候最好有线程…

Latex:画图识别符号

http://detexify.kirelabs.org/classify.html