【Java基础】Java网络编程基础知识
什么是网络编程
网络编程是通过使用套接字来达到进程间通信目的,那什么是套接字呢?其实套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程,具体来看,套接字=IP地址+TCP/UDP + 端口的组合。
网络编程的三要素
网络编程中,通信“双方”要如何找到彼此呢?互联网是通过IP地址来区分上网电脑的,但是通信的“双方”都是物理电脑上跑的进程,在一台电脑上通过端口来区分不同进程和程序,最后,在互联网通信中,我们分UDP和TCP两种协议。所以网络编程的三要素就是:IP地址,端口号,通信协议。
IP地址
IP地址是指互联网协议地址,IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。IP地址编址方案将IP地址空间划分为A、B、C、D、E五类,其中A、B、C是基本类,D、E类作为多播和保留使用。IP地址总共是4个字节,32比特位。
A类:网络号为1个字节,定义最高比特为0,余下7比特为网络号;
B类:网络号为2字节,定义最高比特为10,余下14比特为网络号;
C类:网络号为3字节,定义最高三比特为110,余下21比特为网络号;
D类:不分网络号和主机号,定义最高四比特为1110,表示一个多播地址,即多目的地传输,可用来识别一组主机;
E类:以1111开始,为将来使用保留。E类地址保留,仅作实验和开发用;
另外,全0类地址0.0.0.0表示任意网络。全1的IP地址255.255.255.255是当前子网的广播地址。网络号127。TCP/IP协议规定网络号127不可用于任何网络。其中有一个特别地址:127.0.0.1称之为回送地址(Loopback),它将信息通过自身的接口发送后返回,可用来测试端口状态。
总之:1~126属A类地址,128~191属B类地址,192~223属C类地址,224~239属D类地址。除了以上四类地址外,还有E类地址,但暂未使用。
端口号
端口包括物理端口和逻辑端口。物理端口是用于连接物理设备之间的接口,逻辑端口是逻辑上用于区分服务的端口。TCP/IP协议中的端口就是逻辑端口,通过不同的逻辑端口来区分不同的服务。一个IP地址的端口通过16bit进行编号,最多可以有65536个端口。端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535。
协议TCP/UDP--指网络传输层的协议
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的 SYN 执行 ACK 确认。
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP同样也是传输层的协议,但是由于UDP是无连接的协议,所以没有三次握手过程。
Java中网络编程的几个重要类
Java为网络编程提供了专门的包java.net。下面来看看实现基础网络通信的几个类,也是我们上面总结的几个网络编程要素,除了这些要素外,传输的数据在网络中需要打包等。
InetAddress 此类表示互联网协议 (IP) 地址。
DatagramSocket 此类表示用来发送和接收数据报包的套接字。
ServerSocket 此类实现服务器套接字。
Socket 此类实现客户端套接字(也可以就叫“套接字”)。
DatagramPacket 此类表示数据报包。
UDP网络编程
用UDP协议进行通信,简单的发送数据按照如下4步走:
A. 创建发送端Socket对象DatagramSocket
B. 创建数据,并把数据打包成DatagramPacket
C. 调用Socket对象的发送方法发送数据包
D. 释放资源
接收数据按如下5步走:
A:创建接收端Socket对象DatagramSocket
B:创建一个数据包(接收容器)
C:调用Socket对象的接收方法接收数据包DatagramPacket
D:解析数据包,并显示在控制台
E:释放资源
下面写一个简单的示例程序,先写服务端的接收数据的程序:
public class ReceiveServer {
public static void main(String[] args) throws IOException {
// 创建接收端的Socket对象
DatagramSocket ds = new DatagramSocket(12345); // 创建一个数据包用来接收数据
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length); // 接收数据
ds.receive(dp); // 解析数据
String ipAdd = dp.getAddress().getHostAddress();
String str = new String(dp.getData(), 0, dp.getLength());
System.out.println("地址 " + ipAdd + " 传输的数据为 : " + str); // 释放资源
ds.close();
}
}
客户端的发送程序为:
public class SendClient {
public static void main(String[] args) throws IOException {
// 创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket(); // 创建数据并打包
byte[] bys = "这是UDP传输测试".getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.1.101"), 12345); // 发送数据
ds.send(dp); // 释放资源
ds.close();
}
}
先启动服务端,再启动客户端,最后服务端输出客户端传来的信息:地址 192.168.1.101 传输的数据为 : 这是UDP传输测试
如果多次启动客户端,则会报错端口被占用。
上面的程序虽然实现了基本的通信,但是却有一些问题:
A: 客户端只能传输一条数据,我们希望可以传输多条或者不想传输后再关闭客户端释放资源。
B:服务端和客户端只能接受单线程
为此,将代码改进为键盘录入的多线程版本:
public class ChatRoom {
public static void main(String[] args) throws IOException {
DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(12346); SendThread st = new SendThread(dsSend);
ReceiveThread rt = new ReceiveThread(dsReceive); Thread t1 = new Thread(st);
Thread t2 = new Thread(rt); t1.start();
t2.start();
}
} class ReceiveThread implements Runnable {
private DatagramSocket ds; public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
} @Override
public void run() {
try {
while (true) {
// 创建一个数据包
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length); // 接收数据
ds.receive(dp); // 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println("地址: " + ip + " 数据: " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
} } class SendThread implements Runnable { private DatagramSocket ds; public SendThread(DatagramSocket ds) {
this.ds = ds;
} @Override
public void run() {
try {
// 封装键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("bye".equals(line)) {
break;
} // 创建数据并打包
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.1.101"), 12346); // 发送数据
ds.send(dp);
} // 释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
TCP网络编程
TCP网络编程是面向连接的,用到的套接字是Socket和ServerSocket,其中Socket是客户端用的套接字,其构造方法如下:
Socket()
通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(InetAddress host, int port, boolean stream)
已过时。 Use DatagramSocket instead for UDP transport.
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
创建一个套接字并将其连接到指定远程地址上的指定远程端口。
Socket(Proxy proxy)
创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。
protected Socket(SocketImpl impl)
使用用户指定的 SocketImpl 创建一个未连接 Socket。
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(String host, int port, boolean stream)
已过时。 使用 DatagramSocket 取代 UDP 传输。
Socket(String host, int port, InetAddress localAddr, int localPort)
创建一个套接字并将其连接到指定远程主机上的指定远程端口。
常用的方法如下:
void close()
关闭此套接字。
void connect(SocketAddress endpoint)
将此套接字连接到服务器。
InetAddress getInetAddress()
返回套接字连接的地址。
InputStream getInputStream()
返回此套接字的输入流。
OutputStream getOutputStream()
返回此套接字的输出流。
int getPort()
返回此套接字连接到的远程端口。
SocketAddress getRemoteSocketAddress()
返回此套接字连接的端点的地址,如果未连接则返回 null。
void shutdownInput()
此套接字的输入流置于“流的末尾”。
void shutdownOutput()
禁用此套接字的输出流。
ServerSocket套接字是服务器端的套接字,服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。其构造方法如下:
ServerSocket()
创建非绑定服务器套接字。
ServerSocket(int port)
创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog)
利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr)
使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
常用方法如下:
Socket accept()
侦听并接受到此套接字的连接。
void bind(SocketAddress endpoint)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
void bind(SocketAddress endpoint, int backlog)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
void close()
关闭此套接字。
服务器端主要是获取连接上的客户端Socket,然后接可以获取对应的输入输出流进行读取和写入。
另外,必须先启动服务器,因为TCP是面向连接的,要进行三次握手取得连接后才可以开始写或者读数据。
下面给出一个客户端上传文件的多线程例子:
public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.1.101", 12121); // 封装文本文件
BufferedReader br = new BufferedReader(new FileReader(
"UploadClient.java")); // 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream())); String line = null;
while ((line = br.readLine()) != null) { // 阻塞读
bw.write(line);
bw.newLine();
bw.flush();//刷新
} // Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput(); // 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client); // 释放资源
br.close();
s.close();
}
} public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(12121); while (true) {
Socket s = ss.accept();//每接受一个Socket则新建一个对应的线程处理
new Thread(new UserThread(s)).start();
}
}
} public class UserThread implements Runnable {
//Socket对象
private Socket s; public UserThread(Socket s) {
this.s = s;
} @Override
public void run() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 封装通道内的流
br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 封装文本文件,为了防止名称冲突加上当前时间
String newName = System.currentTimeMillis() + ".txt";
bw = new BufferedWriter(new FileWriter(newName)); String line = null;
while ((line = br.readLine()) != null) { // 阻塞读
bw.write(line);
bw.newLine();
bw.flush();//刷新
} // 给出反馈,客户端可以终止
BufferedWriter bwServer = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush(); } catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(s!=null){
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} }
【Java基础】Java网络编程基础知识的更多相关文章
- 大数据学习笔记——Java篇之网络编程基础
Java网络编程学习笔记 1. 网络编程基础知识 1.1 网络分层图 网络分层分为两种模型:OSI模型以及TCP/IP网络模型,前者模型分为7层,是一个理论的,参考的模型:后者为实际应用的模型,具体对 ...
- Java SE之网络编程:知识框架
- java第九节 网络编程的基础知识
/** * * 网络编程的基础知识 * 网络协议与TCP/IP * IP地址和Port(端口号) * 本地回路的IP地址:127.0.0.1 * 端口号的范围为0-65535之间,0-1023之间的端 ...
- Java网络编程基础(Netty预备知识)
今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...
- Java网络编程和NIO详解开篇:Java网络编程基础
Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...
- 黑马程序员:Java基础总结----网络编程
黑马程序员:Java基础总结 网络编程 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 网络编程 网络通讯要素 . IP地址 . 网络中设备的标识 . 不易记忆,可用 ...
- java网络编程基础——网络基础
java网络编程 网络编程基础 1.常用的网络拓扑结构: 星型网络.总线网络.环线网络.树形网络.星型环线网络 2.通信协议的组成 通信协议通常由3部分组成: 语义部分:用于决定通信双方对话类型 语法 ...
- java网络编程基础
前言 通过网络进行数据传输时,一般使用TCP/UDP进行数据传输.但是两个的区别就是TCP可靠,UDP不可靠.两个的共同之处就是都需要建立socket套接字,将IP地址和端口port进行绑定.但是服务 ...
- [Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...
- C#网络编程基础知识
C#网络编程基础知识一 1.IPAddress类 用于表示一个IP地址.IPAddress默认构造函数 public IPAddress(long address);一般不用 其中Parse()方法最 ...
随机推荐
- CF 369 B. Valera and Contest
http://codeforces.com/contest/369/problem/B 题意 :n, k, l, r, sall, sk,n代表的是n个人,这n个人的总分是sall,每个人的得分大于 ...
- c缺陷与陷阱笔记-第二章 语法陷阱
1.函数的调用和番薯返回值是函数指针的声明 定义一个函数指针,例如 int (*fp)(float),这个函数的返回值是Int,参数是1个float类型,调用这个函数的方法是 (*fp)(),还有f ...
- codeforces #310 div1 D
一开始写了个暴力模拟绳子的摆动轨迹 然后在Test 16 T掉了 后来%了一下别人的代码,发现需要对特殊情况进行特殊处理 首先我们考虑绳子的向右摆动,设当前位置为p,绳子当前长度为L 如果其旋转中心位 ...
- live555源码研究(十)------在编译过程中遇到的问题及解决方法
一.编译testOnDemandRTSPServer.cpp. 在testProgs项目中,加入testOnDemandRTSPServer.cpp进行编译,编译类型是编译成exe文件,在编译过程中会 ...
- Servlet课程0424(三) 通过继承HttpServlet来开发Servlet
//这是第三种开发servlet的方法,通过继承httpservlet package com.tsinghua; import javax.servlet.http.*; import java.i ...
- Android:时间控件
1.选择时间TimePicker 监听器:OnTimeChangedListener(obj,int hour,int minute); 常用: 获取时:getCurrentHour(). 获取 ...
- Tiny4412汇编流水灯代码,Tiny4412裸机LED操作[1]
从今天开始就正式进入到tiny4412的开发学习中了,今天主要看了一下Tiny4412的启动流程及存储器映射及Exynos4412数据手册,用汇编写了一个跑马灯程序(后续会有C语言版本的出来),先说一 ...
- 转载:C++ vector 类学习笔记
声明:本文转载自http://blog.csdn.net/whz_zb/article/details/6827999 vector简介 vector是STL中最常见的容器,它是一种顺序容器,支持随机 ...
- jquery 图片无缝切换
想要和园友分享一下学习jquery的经验.总结,更希望园友提出点建议. 第一次写,有不好的地方请多多见谅! 文笔有限,很多时候不知道怎么来描述,唉.硬伤啊!!那只好多做了,贴代码... ok,废话少说 ...
- Cacti 'graph_xport.php' SQL注入漏洞
漏洞版本: Cacti < 0.8.8b 漏洞描述: Bugtraq ID:66555 Cacti是一套基于PHP,MySQL,SNMP及RRDTool开发的网络流量监测图形分析工具. Cact ...