当前课程知识点:JAVA程序设计进阶 > 第四章 网络编程(上) > 4.5 Socket通信实现 > Video
这一节我们将介绍
如何通过java当中的类
来实现Socket通讯
那我们下面看一下
怎么去创建一个Socket
很幸运的是在java当中
已经有定义好这么一个类
就叫Socket这个类
大家看这个类是大写字母开头的
那我们实际上
只需要直接构造这个
Socket类的对象就行了
这些就是它的构造方法
那我们看一下第二个构造方法
第二个构造方法有两个参数
第一个叫InetAddress address
那这个是指的是说
我要构造的这个Socket
它的远程的目标连接地址是什么
然后第二个参数int port
也就是说我的要连接的
目标的那个对象
它的端口号是什么
那我们再看一下第三个构造方法
那其实和第二个构造方法很类似
只不过是它的组机名
由一个字符串来表示
那我们再看一下第四个构造方法
第四个构造方法总共四个参数
前两个参数用来表示
要连接的目标
这个机器的这个地址和端口号
后两个参数用来表示
我本机的地址和端口号
那我们第五个构造方法
和第四个构造方法是类似的
只不过是说我们的组机地址
用的是字符串
而不是采用InetAddress
这样一个类的对象来表示
那这是一个客户端
Socket的例子
Socket Socket
等于new Socket
然后我们看一下那个两个参数
第一个参数是目标服务器的地址
比如这是127.0.0.1
那这个IP地址
通常指的就是我本机
那为什么要这么写呢
是因为我们自己在调程序
往往只有一台电脑
那我们这台电脑
可以同时启动两个虚拟机
那我们先启动服务端的虚拟机
在那里等着
然后我们这时候
这个是客户端的Socket的话
我们要启动另外一个虚拟机
然后去连接到
服务端的那个虚拟机的
这个程序上
那只不过就是说
这时候你服务端的程序的地址
就是你本机地址
所以我们用127.0.0.1来表示
端口号用的是2000
那这个端口号你取
原则上取什么都可以
只要不取那些1024以下那些
保留端口号就行
然后另外一个要求是说
你这客户端的这个端口号地址
要和你服务器端
等待的那个端口号地址是一致的
我们在写这个
构造这个Socket对象过程当中
注意还需要用try和catch语句
因为它有可能产生异常
那服务端怎么来构造
相对应的Socket对象呢
我们看看
ServerSocket server等于空
然后try Server等于
new ServerSocket2000
大家看到没有
在服务端我们构造的
不是Socket对象
而构造的是ServerSocket对象
那这个ServerSocket对象里面
还有个参数叫2000
那其实这个2000
和我们刚才客户端
想要连接的这个
服务端的那个端口号是一致的
这个必须一致你才连得上
你要不一致的话
你这个你的服务端客户端
就对不上了
那我们在构造这个
ServerSocket过程中
还注意要捕获异常
用try catch来保护它
好 再往下就有socket对象
socket Socket等于空
然后try Socket
等于Server accept
accept这个方法就有意思了
这个方法属于
ServerSocket方法
这种方法我们称之它为阻塞方法
什么叫阻塞方法呢
就是说它是在那里运行
一直等着有客户端
来给它发送Socket连接请求
如果没有客户端
给我们的服务端
发送这个Socket连接请求
accept就一直在那里循环执行
一直不返回
一直等到有客户端的Socket
发连接请求过来
那我们这服务端的
ServerSocket这个对象的话
它就会accept方法
就会返回一个值
那返回是什么呢
返回的是一个Socket对象
而这个Socket对象
就是和我们客户端的Socket对象
进行对应的
当我们构造完服务端
和客户端的这个Socket对象以后
再往下就可以进行网络通讯了
只不过是要网络通讯之前
我们得利用这个Socket对象
来去构建出几个输入输出流
比如我们看第一行代码
PrintStream os
等于new PrintStream
然后里边的参数是
new BufferedOutputStream
带缓冲的输出流
那这里面它又带一个参数
Socket.getOutputStream
那也就是通过
我们的一个Socket对象
它的getOutputStream方法
获得一个输出流
那我们反过来理解
也就是说我拿到这个
Socket输入流以后
外面先给它包了一层
BufferedOutputStream
然后再外面再包一层
PrintStream
这样我们利用PrintStream
就可以来进行这个通讯了
只不过这是个输出流
输出流是干什么用呢
那站在我这个java程序的角度
我构造一个输出流
实际上是往外发信息的
往外发信息
那我们再看一下输入流
DatalnqutStream is
等于new DatalnputStream
然后Socket.getlnputStream
我们通过Socket对象
它的getlnputStream方法
获得它的输入流
紧接着在外面包了一层
DatalnputStream
形成它这个
DatalnputStream对象is
所以我们构造了
这个Socket输入输出流了以后
就是可以用来进行通讯
那输出流是为了往外发东西
输入流是为了能够
接受来自另外一方发送的信息
当然再往下这两行代码
是另外的一种方式
来去构造这个Socket输入流
和输出流
他们都可以使用
当我们构造完这个输入输出流
然后进行读写
也就是read或write以后
完成我们的通讯需求
最终最终可能需要大家
大家要记得关闭我们Socket
在关闭Socket之前
你得先把那个输出流和输入流
都要关闭
比如os.close关闭输出流
is.close关闭输入流
Socket.close
就把这个Socket关闭
注意关闭的顺序是要先关闭流
再关闭我们的Socket
好了 讲了这么一些
基本的原理以后
大家是不是想看一下
到底例子是什么样子的
那我们现在编一个
最简陋的一个聊天程序
叫命令行聊天程序
我们看一下第一行java
import java.io.*
import java.net.*
我们public class TalkClient
这是一个聊天的客户端
我们看一下这个主方法
主方法里面
首先要构造一个Socket
那目标需要
和我们服务端进行连接
那服务端的地址是哪呢
它是127.0.0.1
然后端口号是4700
好了 构造完Socket对象以后
我们下面要构造输入输出流了
那基本思路我们要构造三个
这个输入输出流
第一个输入流叫做键盘输入流
因为我们聊天过程中需要读取
我们用户从键盘上输入的信息
所以我们构造一个
BuferedReader sin
等于new BufferedReader
然后在里面再包一下
new lnputStreamReader
然后最里面就是System.in
System.in是什么呢
就是我们的标准的键盘输入
所以我们这BuferedReader sin
它的主要功能就是捕获获取
我们用户在键盘上的输入
紧接着我们构造第二个流
第二个流叫PrintWriter
它是一个输出流
对象名字叫os
然后等于new PrintWriter
Socket.getOutputStream
这是我们通过Socket对象
获得它的输出流
在外面给它包了一层
PrintWriter
那这个PrintWriter os对象
它的主要作用
就是说从客户端
把信息发送给我们服务端
第三个流BufferedReader is
等于new BufferedReader
然后里面它的参数是
new lnputStreamReader
然后最里面是
Socket.getinputStream
那Socket.getinputStream
是通过这个Socket对象
获得它的输入流
那外面包上这么几层以后
最终得到是BufferedReader
那这个输入流的作用
就是要接收来自于
网络上发给我这个程序的信息
好了 三个流我们构造完了
分别是一个键盘输入流
一个网络输出流
一个网络输入流
下面我们开始接收信息了
我们先构造了一个字符串
readline
readline等于sin.readLine
sin就是sin
这是我们的键盘输入流
也就是说我们从客户端
先获取一下
我们用户都敲了哪一些字符
那获得这个字符以后
下面我们看下面这个语句
while readline.equals bye
也就是说如果用户敲的
不是bye这个字符
这个字符串
那说明聊天还继续
那聊天继续的话
那既然敲这个信息
我就要把它发给网络的那一头
那我怎么发呢
os.println readline
然后紧接着os.flush强制输出
也就是让它强制输出以后
实际上就从我客户端
把我刚才键盘敲出的信息
发送给网络的那一头了
发到那一头了以后
紧接着要做什么事情呢
第一我在自己的屏幕上
写着Client readline
也就是说客户端接收了什么信息
然后马上要打印
Server端给我返回啥信息呢
也就是Server加上is.readLine
然后紧接着我们要再次去获得
我们用户在键盘上的输入
所以readline等于sin.readLine
又获取我们这个用户键盘收入
依次循环到什么时候结束呢
等到我们的有用户敲了bye
这个聊天才算结束
结束完了以后
我们的这个流 os要关闭
is要关闭
然后我们的Socket要关闭
当然在关闭过程当中
我们要捕获一下异常
做一下异常的处理
好了刚才我们刚刚把客户端的程序
给描述清楚了
那服务端的程序又是怎样的呢
我们来看一下服务端的程序
public class TalkServer
TalkServer里面
主方法它有一个
ServerSocket Server等于空
在服务端的话
它首先要声明的是一个
ServerSocket对象
紧接着进行构造
try Server
等于new ServerSocket4700
也就是端口号
也就是说端口号是4700
在实例化过程中
我们要捕获各种各样的异常
然后我们马上构造一个
Socket对象
Socket Socket等于空
紧接着ServerSocket
它的accept方法
接收到来自客户端的
一个Socket请求
然后它也会返回一个Socket对象
那再下来的话
由于这个服务端的Socket对象
也构造成功了
那下面就要进行通讯了
只不过是站在服务端的角度
我要和客户端进行通讯
那服务端的这个通讯的话
实际上它也需要构造三个流
那第一个流它构造的是
Socket输入流
那站在服务端的角度
它的输入流
其实它读取的信息
是来自于网络上
我们客户端发给它的信息
那它构造第二个流
是它的输出流
也就是通过
Socket.getlnputStream
或者它的输出流
那我们站在服务端角度
它的输出流
实际上是往外写东西
那往写东西
实际上就是把我们服务端的内容
发送给我们的客户端
第三个流是它的键盘输入流
也就是说站在服务端角度
它也同样需要接收
来自服务端的这些键盘输入
或者键盘输入了以后
它再把它发送给
我们网络上的客户端
那这几个流构造完了以后
我们就看一下
它到底怎么开始接收信息了
首先站在这个服务端的角度
它要接收来自客户端的信息
所以我们可以看到
is.readLine
就是服务端的输入流
它先读一行 它读的内容
就是客户端发给它的信息
读完以后并把它显示出来
那既然站在服务端角度
我已经接收来自客户端的信息了
我要做一些响应
那我怎么响应呢
那就肯定要有往我的键盘上收入
所以我们看这一段代码第二行
就line等于sin.readLine
也就是我的键盘输入流
读取一行内容
那读的内容如果它不等于bye
也就是说我并不想结束
我们的这个聊天过程
那我就把我的内容
发送给客户端呗
那怎么发送 os.println
把这就是打印 也就是输出
另外os.flush
也就是强制输出
那站在服务端我往外输出
实际上就发送给我的客户端了
那这时候我会在这显示
打印出来说Server加上line
也就是Server它的输入是什么
然后这时候又循环的去接收
来自客户端的信息
也就是Client加上is.readLine
显示完客户端的信息了以后
我们又继续输入这个键盘
line等于sin.readLine
一直循环到键盘敲上bye
结束聊天
那聊天结束以后
我们把os close掉
is close掉 把Socket close掉
这样把这个流和Socket都关闭了
最后的话是要把
我们这个Server给关闭掉
就是这个Server
就是我们的ServerSocket
所以大家现在看到这个
服务端的例子和客户端的例子
其实它大部分内容是一样的
只不过服务端
它要构造一个ServerSocket
然后通过ServerSocket
得到和客户端连接的Socket对象
那得到Socket对象了
就可以构造这些输入输出流
进行IO流的读写
读写完后再把这些流
和这些Socket关闭掉就可以了
所以我们可以看到
网络编程其实到后面
其实就转换成为IO编程
这是我们某一次运行的结果
比如Client 上面敲出hello
然后Server端也敲hello
然后Client说how are you
Server说I am fine thank you
那最后的话
这个两位敲bye的话
这个聊天就结束了
这个聊天程序实际上是
在这个命令行底下进行的
虽然非常简陋
但是你也看到它确实可以
发送网络信息
那需要提醒大家注意是
我们这个程序非常简单
简单到什么程度呢
就是说聊天的时候
都是你说一句 我说一句
如果一个想连续说两句话的话
可能现有这个机制还处理不过来
必须是一人一句
当然我们同学可以把这个程序
再进一步改进使它更加的丰富
这一节我们通过一个
最简单的聊天程序
来呈现了如何通过Socket
来进行java程序之间的通讯
下面总结一下本章的内容
在本章当中
我们介绍了如何通过URL
来访问互联网资源
并介绍了URL相关的对象
比如说URL这个类
URL Connection这个类
以及介绍了 get和port方法
此外我们还介绍了
如何在两个程序之间
进行Socket通讯的原理
以及如何采用java当中的类
来实现Socket通讯
这些就是本章的内容
-1.0 导学
--Video
-1.1 线程的基本概念
--Video
-1.1 线程的基本概念--作业
-1.2 通过Thread类创建线程
--Video
-1.2 通过Thread类创建线程--作业
-1.3 线程的休眠
--Video
-1.3 线程的休眠--作业
-1.4 Thread类详解
--Video
-1.5 通过Runnable接口创建线程
--Video
-1.5 通过Runnable接口创建线程--作业
-1.6 线程内部的数据共享
--Video
-2.0 导学
--Video
-2.1 线程同步的思路
--Video
-2.2 线程同步的实现方式—Synchronization
--Video
-2.3 线程的等待与唤醒
--Video
-2.4 后台进程
--Video
-2.5 线程的生命周期与死锁
--Video
-2.6 线程的调度
--Video
-3.0 导学
--Video
-3.1 线程安全与线程兼容与对立
--Video
-3.2 线程的安全实现-互斥同步
--Video
-3.3 线程的安全实现-非阻塞同步
--Video
-3.4 线程的安全实现-无同步方案
--Video
-3.5 锁优化
--Video
-4.0 导学
--Video
-4.1 URL对象
--Video
-4.2 URLConnection对象
--Video
-4.3 Get请求与Post请求
--Video
-4.4 Socket通信原理
--Video
-4.5 Socket通信实现
--Video
-5.0 导学
--Video
-5.1 Socket 多客户端通信实现
--Video
-5.2 数据报通信
--Video
-5.3 使用数据报进行广播通信
--Video
-5.4 网络聊天程序
--Video
-6.0 导学
--Video
-6.1 Java虚拟机概念
--Video
-6.2 Java虚拟机内存划分
--Video
-6.3 Java虚拟机类加载机制
--Video
-6.4 判断对象是否存活算法及对象引用
--Video
-6.5 分代垃圾回收
--Video
-6.6 典型的垃圾收集算法
--Video
-6.7典型的垃圾收集器
--Video
-7.0 导学
--Video
-7.1 集合框架与ArrayList
--Video
-7.2 LinkedList
--Video
-7.3 HashMap与HashTable
--Video
-7.4 TreeMap与LinkedHashMap
--Video
-7.5 HashSet
--Video
-8.0 导学
--Video
-8.1 Java反射机制
--Video
-8.2 Java静态代理
--Video
-8.3 Java动态代理
--Video
-8.4 Java 反射扩展-jvm加载类原理
--Video
-8.5 Java进阶课程总结
--Video