网络编程TCP和UDP

网络编程:
局域网——城域网——广域网

IP地址、端口
IP地址:网络每个物理节点的唯一标识。类似于一栋楼的编号。
IP:Internet Protocol :负责为网络上每个物理节点编号。
IPv4:32位的2进制数,为了方便机器,于是将32位的IP地址分为4节(每节8位),每节可以指定0~255的数,每节对应平时所说的IP地址的一位数。
IPv6:128位的2进制数,支持更多的IP地址。
端口:一个物理设备上可能有很多个网络程序运行,为了让数据能准确区分到底送达物理节点上哪个程序,于是又给这写程序分配编号——这就是端口,形象来说,端口类似于一栋楼里的房间号。

要指定数据的到达的目标地址,需要同时指定IP地址 + 端口。
端口一共支持65536(2的16次方)个。
公认端口:0~1023范围,HTTP:80 FTP:21 POP3:110
注册端口:1024~49151范围,为一些应用程序绑定了端口。SQLServer:1433 MYSQL:3306
动态端口:系统为应用程序随机分配,一般不推荐程序使用。49152~65535

Java中代表IP地址的类:InetAddress,该类很少单独使用,通常它用于为其他类提供服务——代表IP地址。它有两个子类:Inet4Address、Inet6Address分别代表IPv4和IPv6地址。
1、调用static方法来获取InetAddress(IP地址) InetAddress.getByName(“192.168.0.107”);
2、根据需要调用方法,实际项目:通常是将该对象作为参数传给其他方法。
InetAddress类:代表IP地址,只提供了如下获取InetAddress实例的类方法:
getByName(String host):根据主机名获取对应的InetAddress对象
getByAddress(byte[] addr):根据原始IP地址来获取对应的InetAddress对象
InetAddress提供如下三个方法获取InetAddress实例对应的IP地址和主机名
String getCanonicalHostNmae():获取IP地址的全限定域名
String getHostAddress():返回该InetAddress实例对应的IP地址字符串
String getHorsName():获取此IP地址的主机名
InetAddress getLocalHost():获取本机IP地址对应的InetAddress实例
isReachable():测试是否可以到达该地址

两个编码类:
URLDecoder:解码类,提供静态方法decode(String s,String enc),将乱码字符串转换成普通 字符串。.s指定解码的字符串,enc指定解码字符集形式
URLEncoder:编码类,提供静态方法encode(String s,String enc),将普通字符串转换成applicationxxxxxxxMIME字符串 .s指定编码的字符串,enc指定编码字符集形式

非西欧字符在互联网上URL上传输时,需要使用URLEncoder转成%XX格式,GBK形式时,每个字符转换成两个字节——两位的16进制数。仅包含西欧字符和MIME字符串无需转换。

URL:Uniform Resoure Locator(统一资源定位器),是指向互联网的“资源”的指针。URL代表了互联网上一份资源(文件)的唯一标识。
URL由如下几部分组成
protocol(协议)😕/host(主机部分):port(端口部分)/resourceName(资源)
如:https://www.baidu.com:80/index.html
和URL类似的类还有URI,URI实例代表一个统一资源标识符,不能用于定位任何资源,唯一作用就是解析,而URL包含一个可打开到达该资源是输入流。
该类主要有以下两个方法:
openStream(),打开与此URL的连接,返回一个用于读取该URL资源的InputStream,方便读取远程资源——甚至实现多线程下载。
OpenConnection():打开一个网络连接,返回URLConnection对象,代表了与URL所引用的 远程对象的连接
还有其他简单的方法:
getFile()获取URL的资源名 getHost():获取URL的主机名 getPath()获取URL的路径部分 getPort()获取端口号,getProtocol()获取该URL的协议名称,getQuery()获取该URL的查询字符串的部分
多线程下载网络资源工具实现步骤:
1、先通过url路径创建URL对象,通过URL对象通过openConnection获取HttpURLConnection对象,该对象代表了与网络资源的连接
2、通过HttpURIConnection连接设置连接的方式、参数,再通过getContentLength()获取得到资源大小fileSize
3、根据有多少个线程,用资源大小fileSize除以线程数得到每个线程开始下载的指针位置。
4、创建本地文件,设置文件带下为fileSize,然后关闭文件资源。
5、创建线程,线程run方法创建URL对象,通过openConnection方法获取HttpURLConnection
对象,通过HttpURIConnection连接设置连接的方式、参数,再通过etInputStream():返回一个用于读取该URL资源的InputStream,根据之前设置的指针位置开始读取资源。读取的资源写入本地创建的文件中。

URLConnection:代表了与网络资源的连接,尤其是HttpURIConnection子类,可以方便基于HTTP协议编程。
HttpURIConnection:基于HTTP协议的网络通信工具类。可模拟浏览器发送GET请求、post请求。步骤如下:
通常创建一个和URL的连接并发送请求,读取此URL引用的资源需要如下步骤:
1、通过调用URL对象的openConnection()方法返回URLConnection对象
2、设置URLConnection的参数和普通请求属性。
3、如果只是GET方式的请求,设置完参数后,使用Connect()方法建立和远程资源之间的实际连接即可。如果需要发送POST方式的请求,则需要后去URLConnection实例对应的输出流来发送请求参数。获取之前设置setDoOutput(true)、setDoInput(true),之后调用输出流的print(param)方法发送post参数。
4、远程资源变为可用,程序可以访问远程资源的头字段或通过输入流读取远程资源的数据
在建立和远程资源的实际连接之前,程序可以通过如下方法来设置请求头字段的值:
setAllowUserInteraction():设置该URLConnection的allowUserInteraction请求头字段的值。
setDoInput():设置该URLConnection的doInput请求头字段的值
setIfModifiedSince():设置该URLConnection的ifModifiedSince请求头字段的值
setUserCaches():设置该URLConnection的userCaches请求头字段的值
除此之外,还可以通过如下方法来设置或增加通用头字段:
setRequestProperty(key,value):设置该URLConnection的key请求头字段的值为value
addRequestProperty(key,value):设置该URLConnection的key请求头字段的值为value,当远程资源可用之后,程序可以使用以下访问访问请求字段和内容:
Object getContent():获取该URLConnection的内容
String getHeaderField(String name):获取指定响应头字段的值
getInputStream():返回该URLConnection对应的输入流,用于获取URLConnection响应的内 容。
getOutputStream():返回该URLConnection对应的输出流,用于向URLConnection发送请求参 数。
某些响应头字段经常需要访问,可以通过如下方法:
getContentEncoding():获取content-encoding响应头字段的值
getContentLength():获取content-length响应头字段的值
getContentType():获取content-type响应头字段的值
getData():获取data响应头字段的值
getExpiration():获取expires响应头字段的值
getLastModified():获取last-modified响应头字段的值

如果既要使用输入流读取URLConnection响应的内容,又要使用输出流发送请求参数,则一定要先使用输出流,再使用输入流。
Java 8新增URLPermission工具类,用于管理HttpURLConnection的权限问题,如果在HttpURLConnection安装了安全管理器,通过该对象打开链接就需要先获得权限。

TCP协议网络通信:
TCP/IP通信协议:可靠的网络协议,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路,建立虚拟网络链路后,两端的程序就可以通过虚拟链路进行通信。通过Socket产生IO进行网络通信。IP协议标记形成链路的计算机IP和端口,保证计算机能发送和接收分组数据,IP协议负责将消息从一个主机传送到另一个主机,消息在发送的过程中被分割成一个个小包。TCP协议建立计算机之间的虚拟链路:用于发送和接收数据,TCP协议负责收集一个个的信息包,将其按适当的次序放好传送,接收端收到后再将其正确地还原,TCP协议保证了数据包在传送中的准确无误(主要采用重发机制)
TCP协议:Tranfer Control Protocolo:传输控制协议,采用一种重发机制来保证协议的可靠性。如果A节点将数据发送给B节点,A节点要求B节点收到数据之后,返回一个确认信息。如果A节点没有收到确认信息, A节点认为该信息没有送达,那么A节点会再次重发数据。
TCP协议相当于在两个通信节点之间建立了一个虚拟链路
TCP协议的特点:
特点一:面向连接,先建立连接,才能进行数据的传输,双方必须为连接分配必要的系统内核资源,以管理链接的状态和链接上的传输。,这是一种一对一的,因此TCP不适合广播的应用程序,基于广播的应用程序请使用UDP协议。
特点二:可靠传输:1、tcp采用应答机制:TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功,2、超时重传:发送端发送一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。3、错误校验(去重):TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和。4、流量控制和阻塞管理:流量控制用来避免主机送的过快,而接收方来不及完全收下。

使用ServerSocket创建TCP服务器端:
ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待状态,监听来自客户端请求的方法如下:
Socket accept():如果接收到一个客户端Socket的连接请求,该方法将返回一个与客户端 Socket对应的Socket(每个TCP连接都有两个Socket):否则该方法处于等待状态,线程 也会被阻塞。
ServerSocket提供如下构造器创建ServerSocket对象:
ServerSocket(int port):用指定的端口port来创建一个ServerSocket,该端口应该有一个有效 的端口整数值:0~65535
ServerSocket(int port,int backlog):增加一个用来改变连接队列长度的参数blocklog
ServerSocket(int port,int backlog,InetAddress localAddr):在机器存在多个IP地址的情况下,允 许通过localAddr参数来指定将ServerSocket绑定到指定的IP地址。若不指定,默认为 本地IP地址
ServerSocket使用完毕后,使用close()方法来关闭ServerSocket。通常情况下,服务器端会接收多个客户端请求,因此采用循环监听,
ServerSocket serverSocket = new ServerSocket(30000);
while(true)
{
Socket client = serverSocket.accept();//监听客户端连接
PrintStream ps = new PrintStream(client.getOutputStream());//创建输出流
ps.println(“您好,您收到了服务器的新年祝福”);
ps.close();//关闭输出流
client.close();//关闭socket
}
连接成功之后,使用socket进行通信
客户端通常使用Socket的构造器来连接到指定服务器,Socket通常使用如下两个构造器:
Socket(InetAddress/String remoteAddress,int port):创建连接到指定远程主机、远程端口的Socket,该构造器没有指定本地地址、本地端口,默认使用本地自助机的默认IP地址,默认使用系统动态分配的端口。
Socket(InetAddress/String remoteAddress,int port,InetAddress localAddr,int localPort):创建连接到指定远程主机、远程端口的Socket,并指定本地IP地址和本地端口,适用于本地主机有多个IP地址的情形。
客户端使用上面两个构造器时,程序通常使用String对象指定远程主机,如下:
Socket socket = new Socket(“127.0.0.1”,3000);
执行以上代码将会连接到指定服务器,让服务器端的accept()方法向下执行,于是服务器端和客户端就产生一对互相连接的Socket,连接成功后,服务器端和客户端都是使用各自的Socket进行通信,Socket提供了如下方法来获取输入流和输出流:
InputStream getInputStream():返回该Socket对象对应的输入流,让程序通过该输入流从 Socket中取出数据
OutputStream getOutputSteam():返回该Socket对象对应的输出流,让程序通过该输出流从 Socket中输出数据
客户端代码:
Socket socket = new Socket(“127.0.0.1”,3000);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String line = bufferedReader.readLine();
System.out.println(line);
bufferedReader.close();
socket.close();
Socket设置超时时长:setSoTimeout(int timeout)设置,设置超时时长后,若执行读取操作阻塞超过合理时间之后,会抛出SocketTimeoutException异常,可以捕获处理。
若需要为Socket连接服务器指定超时时长,可以在创建Socket时不指定任何参数,然后再通过connect()连接并指定远程服务器和超时时长,如:
Socket s = new Socket();
s.connect(new InetSocketAddress(host,port),10000);

聊天室实现:
服务端:循环监听、监听返回socket,将该socket添加集合中,就开启一条处理该客户端的线程(线程中读取客户端输入,收到就循环遍历socket集合,输出给每个用户)
客户端:一条线程负责循环读,一条线程负责写,阻塞等到用户键盘输入。

半关闭的socket:
通常通过关闭该输出流表示输出结束,但网络通信时,关闭输出流时对应的Socket也会随之关闭,再也无法从Socket中的输入流读取数据。
但使用以下两个方法关闭输入输出流时,只会关闭Socket的输入流或输出流,用以表示输入输出已经完成,此时还可以继续从Socket中获取:
shutdownInput():关闭该Socket的输入流,还可以通过Socket的输出流输出数据。
shutdownOutput():关闭该Socket的输出流,还可以通过Socket的输入流读取数据。
isInputShutdown():判断该socket是否为半读状态
isOutputShutdown():判断该socket是否为半写状态

使用NIO实现非阻塞Socket通信:
使用NIO如下几个特殊类实现非阻塞式Socket:
Selector:是SelectableChannel对象的多路复用器,希望采用非阻塞方式进行通信的Channel 都应该注册到Selector对象,通过Selector静态方法open()创建Selector实例
Selector可以同时监控多个SelectableChannel的IO状况,一个Selector实例有三个SelectionKey集合:
所有的SelectionKey集合:代表了注册在该Selector上的Channel,这个集合可以通过keys() 方法返回。
被选择的SelectionKey集合:代表了所有可通过select()方法获取的、需要进行IO处理的 Channel,这个集合可以通过selectedKeys()方法返回。
被取消的SelectionKet集合:代表了所有被取消注册关系的Channel,在下一次执行select() 方法时,这些Channel对应的SelectionKey会被彻底删除,程序通常无需访问该集合。
一系列与select()相关的方法:
Int Select():监控所有注册的Channel,当他们中间有需要处理的IO操作时,该防范返回,并 将对应的SelectionKey加入被选择的SelectionKey集合中,该方法返回Channel的数量
Int select(long timeout):可以设置超时时长的select()操作
Int selectNow():执行一个立即返回的select()操作,相对于无参数的select(),该方法不会阻 塞线程。
Selector wakeup():使一个还未返回的select()方法立即返回。
SelectableChannel:代表可以支持非阻塞IO操作的Channel对象,被注册到Selector上,注册关系由SelectionKey实例表示,Selector对象的select()方法允许应该同时监控多个IO Channel
SelectableChannel通过register()方法将其注册到Selector上,当Selector上有IO的某些SelectableChannel上有需要处理的IO操作时,可以调用Selector的select()获取它们的数量,通过selectKeys()方法返回它们对应的集合,通过该集合可以获取所有需要进行IO处理的SelectableChannel集合
SelectableChannel对象支持阻塞和非阻塞两种魔术(所有Channel默认都是阻塞模式),必须使用户非阻塞模式才可以利用非阻塞操作,以下方法设置:
SelectableChannel configureBlocking(boolean lock):设置是否采用阻塞操作
Boolean isBlocking():返回该Channel是否是阻塞

使用NIP实现非阻塞Socket通信的步骤:
1、获取Selector类对象,用于监听所有已经注册在该Selector上的Channel
2、创建ServerSocketChannel服务端socket,调用configureBlocking(false)方法,设置为false, 表示使用非阻塞方式。
3、调用ServerSocketChannel对象的registe()方法将服务端注册到Selector,并指定支持的操作:有接收、读、写、连接等操作。
4、Selector对象调用select循环监听,Selector对象下注册的Channel是否有要处理的IO操作,有的话返回值操作的数量,通过selectedKeys()方法返回所有需要进行IO处理的SelectorChannel。然后遍历这个集合,对这些IO操作进行处理(连接得到服务端中与客户端对应的的socket、设置非阻塞方式、注册到Selector、调用isReadable()判断是否有数据、有数据就获取对应的Channel,创建Buffered读取数据,对数据进行处理)

基于UDP的网络通信:

TCP协议、UDP协议都需要以IP协议为基础,UPD与TCP协议是相对的
实现机制 可靠性 性能
TCP协议: 虚拟链路 可靠 略差
确认、重发机制
UDP协议: 数据报 不可靠 略高
不会重发

UDP和TCP的区别:
TCP:可靠,传输大小无限制,需要连接建立时间,差错控制开销大
UDP:不可靠,差错控制开销小,传输大小限制在64KB以下,不需要建立连接

UDP协议:每个通信节点建立一个Socket,但这两个Socket之间并没有虚拟链路,将要发送的数据封装在待IP+port的数据包中,Socket只要将该数据包发送出去即可,UDP会尽力将数据报送达目的地。传播速度快,UDP没有明显的客户端和服务端。
UDP的特点:
1、面向无连接的协议,通信前不必与对方建立连接,不管对方状态就直接发送
2、不可靠的传输:
3、通信效率高,不需要建立连接,直接发送数据包。
先发送的数据反而可能后到,甚至可能丢失(在网络不好的时候才可能)
DatagramSocket:发送数据报的Socket
DatagramPacket:要发送的数据报,该数据报带IP + Port(端口)
获取DatagramSocket实例后就可以通过如下方法发送和接收数据包
receive(DatagramPacket p):从该DatagramSocket中接收数据包,接收中会阻塞,直到接到
Send(DatagramPacket p):以该DatagramSocket对象向外发送数据包。
数据包DatagramPacket 的构造器
DatagramPacket(byte[] buf,int length):以一个空数据来创建DatagramPacket对象,该 对象的作用是接收DatagranmSocket中的 数据。当接收到该数据报后,还可以通过DatagramPacket对象的getAddress()返回发送该数据报的对象IP地址。getPort()返回目标及其的端口,getSocketAddress()返回数据报的目标SocketAddress。该对象封装了IP地址和端口。

MulticastSocket:广播Socket,是DatagramSocket的子类。
setTimeToLive(ttl):设置数据报要存活多久,如果ttl为1,数据报只能在本地局域网。
如果ttl为32,数据报只能在本站点,如果为64,数据报只能在本地区,如果为128,数据报只能在本大洲。
JoinGroup(InetAddress mcastaddr):加入哪个广播地址.
leaveGroup():离开哪个广播地址

代理服务器:P832–836页

TCP的三次握手
目标:知道TCP的三次握手是用于建立连接。
三次握手即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送三个包以确认连接的建立,在socket编程中,这一过程由客户端执行connect来触发

TCP的4次挥手

Tcp的4次握手,主要说TCp断开链接的时候发送的4个数据包,确保断开链接。
第一次挥手:客户端关闭,发包给服务端请求断开链接
第二次挥手:有服务器端发包给客户端,确认收到客户端请求,之后处理服务端内部收到的数据。
第三次挥手:服务端向客户端发包,同意断开链接
第四次挥手,客户端确认断开连接
第四次挥手后,服务端关闭,客户端需要等待30秒—2分钟内才能关闭,因此使用的端口仍然被占用中。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值