网络
一、TCP和UDP的区别
1、TCP是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
2、UDP是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
UDP
- 将数据及源和目的封装成数据包中,不需要建立连接
- 每个数据报的大小在限制在64k内
- 因无连接,是不可靠协议
- 不需要建立连接,速度快
UDP就像是在邮局邮递包裹。只管发送,不管对方能不能收到。
TCP
- 建立连接,形成传输数据的通道。
- 在连接中进行大数据量传输
- 通过三次握手完成连接,是可靠协议
- 必须建立连接,效率会稍低
TCP就像是打电话,必须接通之后才能说话。
TCP的三次握手协议:
1.客户端发送一个连接请求到服务器,如果没有收到响应或者服务器返回失败则客户端返回失败,不能正确连接。
2.服务器端在接收到连接请求后,发回一个同意请求连接,返回给客户端,并且等待客户端的第三次回应,如果没有回应,服务器端关闭连接。
3.客户端端收到服务器的同意请求后,再次发送一个同意连接。至此连接建立。剩下的就是TCP数据交互过程。
二、建立网络连接
服务器与客户端通过建立soket套接字进行通信,套接字其实就是地址与端口号的组合
UDP客户端编程涉及的步骤是4个部分:
使用到的类:DatagramSocket与DatagramPacket
- 获取socket对象
- 对数据进行封包
- 通过socket对象把数据包发送出去
- 把连接关闭
TCP服务端编程涉及的步骤是4个部分:
同样,客户端与服务器端是两个独立的应用程序。
- 使用到的类Socket和ServerSocket
- 建立客户端和服务器端
- 建立连接后,通过Socket中的IO流进行数据的传输
- 关闭socket
程序实例
UDP:
Server端:
package net; import java.net.*; import java.io.*; public class TestUDPServer { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub byte buf[] = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); DatagramSocket ds = new DatagramSocket(5678); while(true){ ds.receive(dp); ByteArrayInputStream bais = new ByteArrayInputStream(buf); //从字节数组中读取数据 DataInputStream dis = new DataInputStream(bais); //将字节转化成LONG类型的数 System.out.println(dis.readLong()); //将字节数组构建成一个字符串 } } }
Client端:package net; import java.net.*; import java.io.*; public class TestUDPClient { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub long n = 1000000L; ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在内存中创建了一个字节数组,将一根管道连接到这块内存中 DataOutputStream dos = new DataOutputStream(baos); dos.writeLong(n); //将这个数据写到相应的内存中 byte[] buf = baos.toByteArray(); //将内存中的数据转换成字节数组 DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",5678)); DatagramSocket ds = new DatagramSocket(9999); ds.send(dp); ds.close(); } }
TCP:Server端:
import java.net.*; import java.io.*; public class TCPServer { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ServerSocket ss = new ServerSocket(6666); //规定连接的端口 while(true){ Socket s = ss.accept(); //接受连接 阻塞式 DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF()); //阻塞式 dis.close(); s.close(); } } }Client端:
package net; import java.io.*; import java.net.*; public class TCOClient { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub Socket s = new Socket("127.0.0.1",8189); //申请链接 OutputStream os = s.getOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("hello server!"); dos.flush(); dos.close(); s.close(); } }
以上是应用TCP和UDP进行通信的两个实例
三、问题
1、套接字超时
在套接字读取信息的时候,读取操作阻塞,最终会受到底层操作系统的影响导致超时,为了不让阻塞时间过长,我们可以设置合理的超时时间。
setSoTimeout方法为套接字设置了超时值,但是当读写操作未完成的时候达到了超时时间,抛出SocketTimeoutException异常。
当客户端请求服务器端连接的时候,超时。
应该用connet(new InetSocketAddress(host,port),timeout);构建套接字并且设置超时时间。
例:Socket s = new Socket();
s.connect(new InetSocketAddress(host,port),timeout);
2、因特网地址
在主机名和网络地址之间进行转换可以应用InetAddress类对象
代码:
import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressTest { public static void main(String[] args) throws UnknownHostException { if(args.length > 0){ String host = args[0]; InetAddress [] addresses = InetAddress.getAllByName(host); for(InetAddress a : addresses) { System.out.println(a); } } else{ InetAddress localHostAddress = InetAddress.getLocalHost(); //获取本地地址 InetAddress address = InetAddress.getByName("time-A.timefreq.bldrdoc.gov"); //获取地址 InetAddress[] address1 = InetAddress.getAllByName("baidu.com"); //获取所有的主机 System.out.println(address.getHostName()); System.out.println(address); System.out.println(localHostAddress); for(int i = 0; i < address1.length; i++){ System.out.println(address1[i]); } } } }
3、半关闭套接字功能:套接字连接的一端可以终止其输出,同时仍旧可以接收来自另一端的数据。使用于一站式的服务
实现:Socket socket = new Socket(host,post);
socket.shutdownOutput();
4、可中断套接字
在我们平时点解连接的时候,往往会有一个终止访问的按钮,用来终止当前的访问,但是当一个线程被阻塞的时候,无法进行和用户的交互,直至操作成功或者超时。
应用java.nio包中提供的一个新特性SocketChannel类实现。
SocketChannel channel = new SocketChannel.open(new InetSocketAddress(host,port));
通道没有与之相对应对的流,在不处理缓冲区的情况下,可使用Scanner类从SocketChannel中读取信息,Scanner in = new Scanner(channel);
OutputStream outStream = Channels.newOutputStream(channel);
这样可以中断一个阻塞的线程,当这个套接字发成阻塞的时候可以进行中断操作。
5、URL和URI
URL是统一资源定位符,URI是统一资源标识符。URL是URI的一种特例。URN是统一资源名称。
URL 解析:
- 协议为(protocol):http
- 主机为(host:port):www.runoob.com
- 端口号为(port): 80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
- 文件路径为(path):/index.html
- 请求参数(query):language=cn
- 定位位置(fragment):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。
在java.net包中定义了URL类,该类用来处理有关URL的内容。对于URL类的创建和使用,下面分别进行介绍。java.net.URL提供了丰富的URL构建方式,并可以通过java.net.URL来获取资源。
URLConnection类为解析URL提供了更多的方法,URLConnection connection = url.openConnection();
具体的方法可参考API.
6、端口
端口号范围为0到65535,其中0到1023的端口号一般分配给一些服务。比如FTP服务(21),SMTP(25)服务,HTTP(25)服务,135分配给RPC(远程过程调用)等;从1024到65535的端口号供用户自定义的服务使用。
注:此博客是作者初学笔记,仅供参考。