Java基础——网络编程
一、网络编程概述
概述:
Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。
Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
基础:
网络编程的目的:
网络编程的目的就是指直接或间接地通过网络协议与其它计算机进行通讯。
主要存在的问题:
如何准确地定位网络上一台或多台主机
找到主机后如何可靠高效地进行数据传输。
传输数据需要遵守一定的协议,被广泛运用的是TCP/IP协议
协议模型:
通信要素:
IP地址:InetAddress
网络中设备唯一标识;本地回环地址(localhost):127.0.0.1;不易于记忆,易于记忆的是域名:
域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。
端口:port
为了进行应用程序的标识区分,就提供了一些数字来标识应用程序。比方QQ 用4000来标识,我的电脑QQ发消息,发送到IP 地址是: 192.168.0.1 的编号为4000的应用程序上。而这些数字就是(逻辑)port。
端口号限定在0-65536之间,比如常见的MySQL(3306),http(80),一般我们应该使用1024以后的端口通信避免通信端口冲突;
端口号与IP地址的组合得出一个网络套接字——Socket。
二、InetAddress类的创建和使用
InetAddress类用来封装我们前面讨论的数字式的IP地址和该地址的域名。
1.实例化
通过 getLocalHost()——本机、getByName()以及getAllByName()三个静态方法进行访问
2.两个方法:
String getHostName():获取InetAddress对象的域名;
String getHostAddress():获取InetAddress对象的IP地址;
实例:
public static void main(String[] args) throws UnknownHostException {
InetAddress address = InetAddress.getByName("www.atguigu.com");
System.out.println("address = " + address);
System.out.println(address.getHostName());
System.out.println(address.getHostAddress());
}
三、网络通信协议
1.网络通信协议
对速率、传输代码、代码结构、传输控制步骤、出错控制等的指定标准
2.传输协议的分层思想
采用分层的思想,同层可以通信,上一层可以调用下一层,而与再下一层无关系
传输层有两个重要协议:
TCP:传输控制协议
UDP:用户数据报协议
3.TCP、UDP协议概述
更详细的关于UDP TCP的介绍,参照网友回答:
TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快
现在Internet上流行的协议是TCP/IP协议,该协议中对低于1024的端口都有确切的定义,他们对应着Internet上一些常见的服务。这些常见的服务可以分为使用TCP端口(面向连接)和使用UDP端口(面向无连接)两种。
说到TCP和UDP,首先要明白“连接”和“无连接”的含义,他们的关系可以用一个形象地比喻来说明,就是打电话和写信。两个人如果要通话,首先要建立连接——即打电话时的拨号,等待响应后——即接听电话后,才能相互传递信息,最后还要断开连接——即挂电话。写信就比较简单了,填写好收信人的地址后将信投入邮筒,收信人就可以收到了。从这个分析可以看出,建立连接可以在需要痛心地双方建立一个传递信息的通道,在发送方发送请求连接信息接收方响应后,由于是在接受方响应后才开始传递信息,而且是在一个通道中传送,因此接受方能比较完整地收到发送方发出的信息,即信息传递的可靠性比较高。但也正因为需要建立连接,使资源开销加大(在建立连接前必须等待接受方响应,传输信息过程中必须确认信息是否传到及断开连接时发出相应的信号等),独占一个通道,在断开连接钱不能建立另一个连接,即两人在通话过程中第三方不能打入电话。而无连接是一开始就发送信息(严格说来,这是没有开始、结束的),只是一次性的传递,是先不需要接受方的响应,因而在一定程度上也无法保证信息传递的可靠性了,就像写信一样,我们只是将信寄出去,却不能保证收信人一定可以收到。
TCP是面向连接的,有比较高的可靠性,
一些要求比较高的服务一般使用这个协议,如FTP、Telnet、SMTP、HTTP、POP3等,而UDP是面向无连接的,使用这个协议的常见服务有DNS、SNMP、QQ等。对于QQ必须另外说明一下,QQ2003以前是只使用UDP协议的,其服务器使用8000端口,侦听是否有信息传来,客户端使用4000端口,向外发送信息(这也就不难理解在一般的显IP的QQ版本中显示好友的IP地址信息中端口常为4000或其后续端口的原因了),即QQ程序既接受服务又提供服务,在以后的QQ版本中也支持使用TCP协议了。
更多三次握手(四次分手)的请参见:http://www.jellythink.com/archives/705
更详细的TCP、UDP协议请参见:http://blog.csdn.net/li_ning_/article/details/52117463
四、网络编程实例
1。Socket
2.Socket编程实例
TCP
客户端向服务端发送消息,服务端接收
// 客户端
@Test
public void client() {
Socket cs = null;
OutputStream out = null;
try {
// 1.创建socket对象,指明服务端的IP地址与端口号
cs = new Socket(InetAddress.getByName("127.0.0.1"), 9898);
// 2.获取socket对象的输出流发送数据
out = cs.getOutputStream();
// 3.具体的输出过程(IO的操作)
out.write("客户端信息".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 流的关闭
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (cs != null) {
try {
cs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 服务端
@Test
public void server() {
ServerSocket ss = null;
Socket accept = null;
InputStream in = null;
try {
// 1.创建一个ServerSocket对象指明自身的端口号
ss = new ServerSocket(9898);
// 2.调用accept方法返回socket对象
accept = ss.accept();
// 3.通过返回的socket对象的输入流获取数据
in = accept.getInputStream();
// 4.流的操作,详见IO(输入流主要作读取)
int len;
byte[] bytes = new byte[15];
while ((len = in.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
// 可以得出访问者信息
System.out.println("收到来自于:"+accept.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 流的关闭
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (accept != null) {
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//操作步骤请参见代码注释
客户端向服务端发送消息,服务端接收,并发送发聩消息
// 客户端
@Test
public void client() {
Socket socket = null;
OutputStream out = null;
InputStream in = null;
try {
// 创建socket
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9898);
// 得到输出流
out = socket.getOutputStream();
// 利用IO写数据
out.write("我是客户端,收到请回答,over over!".getBytes());
// 读取服务端反馈数据
in = socket.getInputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 按照流的打开顺序,逆序关闭
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
@Test
// 服务端
public void server() {
ServerSocket ss = null;
InputStream in = null;
Socket accept = null;
OutputStream out = null;
try {
// 创建服务端Socket
ss = new ServerSocket(9898);
// 接收消息
accept = ss.accept();
// 取得输入流返回值
in = accept.getInputStream();
// 利用IO读取
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
// 发送反馈消息(利用socket得输出流)
out = accept.getOutputStream();
out.write("我是服务端,已经收到,over over!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (accept != null) {
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//这样会发现,程序无法停止,也就是通信连接不正常!
原因就是inputStream是阻塞式的,服务端无法确定客户端何时可以发送完成数据(不像第一个案例,发送完客户端就结束了),所以就一直在等
改为显式关闭客户端的输入即可:
// 客户端
@Test
public void client() {
Socket socket = null;
OutputStream out = null;
InputStream in = null;
try {
// 创建socket
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9898);
// 得到输出流
out = socket.getOutputStream();
// 利用IO写数据
out.write("我是客户端,收到请回答,over over!".getBytes());
// 显式的告诉服务端已经发送完毕!
socket.shutdownOutput();
// 读取服务端反馈数据
in = socket.getInputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 按照流的打开顺序,逆序关闭
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
@Test
// 服务端
public void server() {
ServerSocket ss = null;
InputStream in = null;
Socket accept = null;
OutputStream out = null;
try {
// 创建服务端Socket
ss = new ServerSocket(9898);
// 接收消息
accept = ss.accept();
// 取得输入流返回值
in = accept.getInputStream();
// 利用IO读取
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
// 发送反馈消息(利用socket得输出流)
out = accept.getOutputStream();
out.write("我是服务端,已经收到,over over!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (accept != null) {
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端发送文件给服务端,服务端保存到本地,并发送“保存成功”的反馈,然后关闭TCP连接
// 客户端
@Test
public void client() {
FileInputStream in = null;
Socket socket = null;
OutputStream out = null;
InputStream inFromServer = null;
File file = new File("D:\\test\\1.jpg");
try {
// 建立socket
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9898);
out = socket.getOutputStream();
// 读取本地文件,写入socket的输出流
in = new FileInputStream(file);
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
// 写入输出流(偏移量0,长度len)
out.write(bytes, 0, len);
}
// 显式表明关闭
socket.shutdownOutput();
// 接收服务端的反馈消息
inFromServer = socket.getInputStream();
while ((len = inFromServer.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
} } catch (IOException e) {
e.printStackTrace();
} finally {
// 逆序关闭流
if (inFromServer != null) {
try {
inFromServer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 服务端
@Test
public void server() {
ServerSocket ss = null;
Socket accept = null;
InputStream in = null;
File file = new File("D:\\test\\2.jpg");
FileOutputStream out = null;
OutputStream outToClient = null;
try {
// 新建服务端socket
ss = new ServerSocket(9898);
accept = ss.accept();
// 获取输入流,并保存到本地文件
in = accept.getInputStream();
out = new FileOutputStream(file);
// 保存到本地
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
System.out.println("来自于:"+accept.getInetAddress().getHostAddress());
// 发送反馈信息
outToClient = accept.getOutputStream();
outToClient.write("发送成功,服务端保存完毕!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outToClient != null) {
try {
outToClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (accept != null) {
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 依旧要显式关闭(这方面的改进请参见NIO)
UDP
实例:
// 发送端
@Test
public void send() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
String str = "UDP发送的数据包";
byte[] bytes = str.getBytes();
// 创建一个数据报(不大于64K),记录了数据信息与发送端与接收端的信息(IP、端口号)
DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length,
InetAddress.getByName("127.0.0.1"),9898);
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
}
// 接收端
@Test
public void receive() {
DatagramSocket ds = null;
try {
// 一样需要服务端指明端口
ds = new DatagramSocket(9898);
// 接收数据报
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length);
ds.receive(dp);
// 数据已经到bytes中
System.out.println(new String(dp.getData(),0,dp.getLength()));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
}
UDP更加详细的实例与讲解,参见:http://blog.csdn.net/ns_code/article/details/14128987
3.URL编程
为了表示URL,java.net包中实现了类URL(就像File类对应一个文件,Java中使用对象的形式来表示)。
URL常见的使用实例,请参见:http://www.cnblogs.com/wzy330782/p/5487541.html
构造器
常用方法:
示例:(在tomcat开启一下,在examples中添加资源)
@Test
public void test1() {
try {
URL url = new URL("http://127.0.0.1:8080/examples/1.jpg");
System.out.println(url.getProtocol());// 协议名
System.out.println(url.getPort());// 端口号
System.out.println(url.getFile());// 文件名
System.out.println(url.getQuery());// 获取查询名
System.out.println(url.getRef());// 返回文档标记
} catch (IOException e) {
e.printStackTrace();
}
}
结果:
获取URL资源
采用openStream获取输入流的方式
@Test
public void test1() {
InputStream in = null;
FileOutputStream out = null;
try {
URL url = new URL("http://127.0.0.1:8080/examples/1.jpg");
System.out.println(url.getFile());// 文件名
// 保存服务端URL对应的资源文件
in = url.openStream();
// 利用IO流进行文件的读取
int len;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File("D:\\test\\2.jpg"));
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//流的关闭
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
采用URLConnection进行与服务器的交互(有读取也有输出),这里不赘述
Java基础——网络编程的更多相关文章
- java基础-网络编程(Socket)技术选型入门之NIO技术
java基础-网络编程(Socket)技术选型入门之NIO技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传统的网络编程 1>.编写socket通信的MyServer ...
- 二十三、Java基础--------网络编程
Java中另一个重要技术就是网络编程了,为了更好的学习web方向的知识,有必要对java之网络编程好好学习,本文将围绕网络编程技术进行分析. 常见的网络协议:UDP.TCP UDP 1. 将数据源和目 ...
- Java基础——网络编程(二)
一.套接字 Socket 网络驱动程序提供给应用程序编程的接口和一种机制,可以比喻成一个港口码头 应用程序只要把货放在这,就算完成了货物的运送.它在应用程序中创建,通过一种绑定机制与驱动程序建立关系, ...
- Java基础——网络编程(一)
本文主要记录网络编程的一些基础知识,学了前班部分,对专业术语有些蒙,但是,收货也是很多很多的.观察了自己计算机的进程,查找其他网络地址的IP,对互联网的层次关系有了更深一步的了解.下面多是概念的摘录, ...
- java基础—网络编程
一.网络基础概念 首先理清一个概念:网络编程 != 网站编程,网络编程现在一般称为TCP/IP编程.
- JAVA基础——网络编程之网络链接
一.网络编程基本概念 1.OSI与TCP/IP体系模型 2.IP和端口 解决了文章最开始提到的定位的问题. IP在互联网中能唯一标识一台计算机,是每一台计算机的唯一标识(身份证):网络编程是和远程计算 ...
- Java基础——网络编程(三)
TCP 网络编程 -- tcp 分为客户端和服务端 -- 客户端对应的对象是 Socket -- 服务端对应的对象是 ServerSocket -- 如果客户端先启动,则出现 connection r ...
- 梦入IBM之java基础-网络编程
如今我们来谈谈最后的内容:网络编程: 1):TCP中是线程与线程进行通讯!内部的执行机制是这种:先有一个线程去监听某个port.然后假设有Socket连接上来了以后,server会生成一个Socket ...
- Java基础-网络编程1
网络编程 Socket 基本概念 C/S结构 :全称为Client/Server结构,是指客户端和服务器结构.常见程序有QQ.迅雷等软件. B/S结构 :全称为Browser/Server结构,是指浏 ...
随机推荐
- 有时间,可以研究哈redis的源代码
1 2 3 4 留位,以后自己用!
- UVALive 4025 Color Squares(BFS)
题目链接:UVALive 4025 Color Squares 按题意要求放带有颜色的块,求达到w分的最少步数. //yy:哇,看别人存下整个棋盘的状态来做,我什么都不想说了,不知道下午自己写了些什么 ...
- 六.安装jdk(基于Centos7安装)
1.我把java安装到/usr/local/jdk目录下面,所以,新建文件夹如下 2.把下载到的文件上传至Linux服务器 笔者使用wget命令直接把文件下载到服务器"wget http:/ ...
- PHP-------- JQUERY方式
JQUERY方式 1.根据ID取元素,Jquery对象 var div = $("#one"); 2.根据class取 var div = $(".test&quo ...
- MaBatis(5)输入/输出映射
本次全部学习内容:MyBatisLearning 输入映射: 通过parameType指定输入参数的类型,类型可以是简单类型,hashmap,pojo等 传递pojo的包装对象 需求: 即 ...
- leetcode 78. Subsets 、90. Subsets II
第一题是输入数组的数值不相同,第二题是输入数组的数值有相同的值,第二题在第一题的基础上需要过滤掉那些相同的数值. level代表的是需要进行选择的数值的位置. 78. Subsets 错误解法: cl ...
- OpenFlow, SDN, and NFV
OpenFlow An open standard to innovative protocols in production networks provides a standardized hoo ...
- imageNamed和dataWithContentsOfFile的区别(1)
imageNamed和dataWithContentsOfFile的区别 imagecacheuiviewextensionprocessingxcode 最近老是受iphone内存问题的困扰,找了些 ...
- peripheralStateNotificationCB
/********************************************************************* * @fn peripheralStateNotifica ...
- STL中sort、priority_queue、map、set的自定义比较函数
STL中,sort的默认排序为less,也就是说从小到大排序:priority_queue默认是less,也就说大顶堆:map默认是less,也就说用迭代器迭代的时候默认是小的排在前面:set默认是l ...