目录

双项通信:

 优化1:

优化2:

一对多: 

 总结:一对一通信,一对多通信都是TCP通信的实现,都是双项通信,只有在两机之间连接之前,才有服务端和客户端的区分,而在连接之后就不在有服务端和客户端了,双方都可以互相发送消息


首先需要声明:部分图片来自百战尚学堂

客户端(Socket)和服务端(ServerSocket)连接的前提是主机之间已经通过TCP协议进行了三次握手,客户端和服务端建立连接的基础是主机之间已经通过TCP协议通信的基础之上的

而服务端和客户端在连接之后就没有主客之分了

单项通信我们上一篇文章已经讲过了,今天我们来讲讲双项通信:

java全双工TCp javatcp双向通信_运维

单项通信就是客户端固定位发送端,服务端固定为接收端。而双项通信是没有固定的发送端和接收端,双方都可以互相通信,此时我们通过代码讲解一下:

双项通信:

首先我们需要创建服务端ServerSocket对象,因为如果先创建客户端那客户端跟谁连接呢?然后服务端传递参数监听8888端口,然后通过accept方法获取监听器对象,此时这个方法会导致线程阻塞,直到监听器对象连接到客户端才会返回就绪状态

服务端需等待客户端发送的信息,然后服务端才能向客户端发送信息

java全双工TCp javatcp双向通信_java_02

然后我们创建客户端Socket对象,通过构造方法并传递服务器的IP地址,以及端口号8888,我们需要先向服务端发送信息,才能接收服务端发送的信息

java全双工TCp javatcp双向通信_java_03

 此时我们就可以通过运行服务端和客户端实现双项通信

java全双工TCp javatcp双向通信_java_04

java全双工TCp javatcp双向通信_java全双工TCp_05

java全双工TCp javatcp双向通信_java_06

java全双工TCp javatcp双向通信_网络_07

 优化1:

但是我们的代码还是不够完善,因为客户端和服务端接收消息都是在同一个线程里的,那么就肯定会涉及到先后的问题而且只能读一句,那么我们在聊天的时候不可能只跟别人说一句话吧,此时我们就需要对代码进行更改,将发送信息和接收消息变为两个线程,让他们并发运行

 首先我们现在服务端实现一个发送消息的线程关于代码如何写的,我的注释都有解释,大家请耐心观看一下

java全双工TCp javatcp双向通信_java全双工TCp_08

 然后我们创建接收消息的线程,代码的实现逻辑注释都有解释 

java全双工TCp javatcp双向通信_java_09

然后就是我们的主线程了,此时我们可以看到我们将对应客户端的Socket对象从try的小括号里移了出来因为这个主线程在运行完之后就会死亡,那么try-with-resource这种语法就会将小括号里可以关的都关闭,如果对应客户端的Socket对象关闭了,那么发送消息的线程和接收消息的线程通过什么获取输入输出流呢?所以对应客户端的Socket对象不能在主线程死亡的时候关闭

java全双工TCp javatcp双向通信_java_10

 而服务端此时的代码就优化完毕了,现在我们来写客户端的发送和接收线程,其实客户端的线程是和服务端一样的所以我们就直接复制了

而客户端的主线程也是一样,客户端Socket对象不能在主线程死亡的时候关闭,所以我们这里就不能使用try-with-resource语法,就用普通的try{...}catch(){...}

java全双工TCp javatcp双向通信_java_11

验证点对点通信

java全双工TCp javatcp双向通信_运维_12

java全双工TCp javatcp双向通信_java全双工TCp_13

优化2:

 但是我们可以发现好像这个点对点通信的代码还可以优化,我们看昂,这个服务端和客户端在连接过后就没有主客之分了,而服务端和客户端都有一串相同的代码,那就是发送消息的线程和接收消息的线程,那我们能不能将服务端和客户端写到同一个类中呢?

显然是可以的此时我们创建一个新的类来优化服务端和客户端 

首先我们在主类中创建输入,当输入为server,<port>的时候创建服务端,当输入为<IP>,<port>的时候创建客户端,然后将输入通过split()方法拆分,通过if判断split拆分的数组的第一个元素是否为server,当我们创建好服务端/客户端对象后,创建发送消息and接收消息的线程

java全双工TCp javatcp双向通信_java_14

 发送消息的线程还是和刚刚写的一样:

java全双工TCp javatcp双向通信_运维_15

 接收消息的线程也一样

java全双工TCp javatcp双向通信_服务器_16

此时我们可以通过两次运行此类来创建服务端和客户端,如果不能运行两次同样的类的,找到上边栏的这个按钮

java全双工TCp javatcp双向通信_java_17

 然后点击这个进行配置

java全双工TCp javatcp双向通信_java全双工TCp_18

然后点击这个

java全双工TCp javatcp双向通信_服务器_19

选择允许多实例

java全双工TCp javatcp双向通信_网络_20

 然后就可以运行两次相同类了 ,然后我们就可以无限制的发送消息和接收消息了,因为这是两个线程并发运行的,互不干扰

java全双工TCp javatcp双向通信_java_21

java全双工TCp javatcp双向通信_网络_22

一对多: 

那么学到了这里大家应该已经会了点对点的通信了,那么我们可以实现一下一对多的通信,一对多的通信其实很简单嘛,就是将服务端的监听方法accept()方法循环一下不就可以实现监听器一直循环端口了吗,那此时不就形成了一对多的通信了吗

如果没有理解我们通过代码来实现看看:

我们就还是通过之前的代码更改一下,改的地方不多就在监听端口的时候给了个死循环让服务端一直监听某个端口监听到数据过后返回服务端所对应的Socket对象并且每个对应的服务端Socket对象都创建接收消息和发送消息的线程并启动

java全双工TCp javatcp双向通信_网络_23

而服务端没啥区别,就是把下面创建线程的代码放到了else里边,其实放外边也没所谓,一样的效果

java全双工TCp javatcp双向通信_java_24

 此时我们运行此类,一个服务端,两个客户端

java全双工TCp javatcp双向通信_网络_25

java全双工TCp javatcp双向通信_运维_26

java全双工TCp javatcp双向通信_服务器_27

只有在两机之间连接之前,才有服务端和客户端的区分,而在连接之后就不在有服务端和客户端了,双方都可以互相发送消息

 明天我们来写通过TCP实现聊天室