TCP/IP 網路模式
| |||||||||||||||||||||||||||||||||||||
應用層 #如HTTP、FTP、DNS | |||||||||||||||||||||||||||||||||||||
##傳輸層如TCP、UDP | |||||||||||||||||||||||||||||||||||||
#網路層如IP、ICMP、IGMP
| |||||||||||||||||||||||||||||||||||||
鏈鋸層如驅動程式、介面 |
方法聲明 | |||||||||||||||||||||||||||||||||||||
InetAddress getAddress() | |||||||||||||||||||||||||||||||||||||
int getPort() | |||||||||||||||||||||||||||||||||||||
byte[] getData() | |||||||||||||||||||||||||||||||||||||
int getLength() | |||||||||||||||||||||||||||||||||||||
## 2、DatagramSocket DatagramSocket類似與碼頭,實例物件就可以傳送和接收DatagramPacket資料包,在建立傳送端和接收端的DatagramSocket物件時,所使用的建構方法有所不同。 DatagramSocket建構方法: ①DatagramSocket() 收到端的Data 用於建立物件時,在建立物件時,並沒有指定連接埠號碼,此時,系統會傳送端的DatagramSocket物件時,在建立物件時,並沒有指定連接埠號,此時,指派一個沒有被其他網路程式使用的連接埠號碼。 ②DatagramSocket(int port) 此方法可用於建立接收端的DatagramSocket對象,可建立傳送端的DatagramSocket對象,在建立接收端的DatagramSocket對象,可建立傳送端的DatagramSocket對象,在建立接收端的DatagramSocket一個連接埠號,這樣就可以監聽指定的連接埠。 ③DatagramSocket(int port,InetAddress addr) 使用此建構方法在DatagramSocket時,不僅指定連接埠號碼,也指定了相關的IP位址,此情況適用於計算上有多塊網路卡的情況。
3、UDP 网络程序 在通信时只有接收端程序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。示例: 1 import java.net.DatagramPacket; 2 import java.net.DatagramSocket; 3 4 //接收端程序 5 public class Example2 { 6 public static void main(String[] args) throws Exception{ 7 //创建一个长度为1024的字节数组,用于接收数据 8 byte [] buf = new byte[1024]; 9 //定义一个DatagramSocket对象,监听的端口为8954 10 DatagramSocket ds = new DatagramSocket(8954); 11 //定义一个DatagramPacket对象,用于接收数据 12 DatagramPacket dp = new DatagramPacket(buf,1024); 13 System.out.println("等待接收数据"); 14 ds.receive(dp); //等待接收数据,如果没有数据则会阻塞 15 //调用DatagramPacket的方法获得接收的消息,包括内容、长度、IP地址和端口号 16 String str = new String(dp.getData(),0,dp.getLength()) 17 +"from"+dp.getAddress().getHostAddress()+":"+dp.getPort(); 18 System.out.println(str); //打印收到的信息 19 ds.close(); //释放资源 20 } 21 } 22 23 24 import java.net.DatagramPacket; 25 import java.net.DatagramSocket; 26 import java.net.InetAddress; 27 28 //发送端程序 29 public class Example3 { 30 public static void main(String[] args) throws Exception { 31 //创建一个DatagramSocket对象 32 DatagramSocket ds = new DatagramSocket(3000); 33 String str = "Hello World!"; //要发送的数据 34 /* 35 * 创建一个要发送的数据包,包括发送数据,数据长度,接收端IP地址以及端口号 36 */ 37 DatagramPacket dp = new DatagramPacket(str.getBytes(),str.length(), 38 InetAddress.getByName("localhost"),8954); 39 System.out.println("发送消息"); 40 ds.send(dp); //发送数据 41 ds.close(); //释放资源 42 } 登入後複製 运行结果 发送消息 等待接收数据 Hello World!from127.0.0.1:3000 登入後複製 解析:发送货物(数据)前,确定到货码头是否能接收。 创建空间(数据容器)接收货物(数据),创建码头【DatagramSocket(8954)】并实时监听发货码头发货通道(端口),创建集装箱并将空间加入用于接收货物,一直等待接收货物,接收码头将货物填充到集装箱中,获取到货物信息(数据等信息)。 发送货物需要建一个码头【DatagramSocket(3000)】,码头可指定发送通道即端口(也可以不指定发送通道),将要发送货物(数据)装进集装箱(DatagramPacket )中,并指定发送到的码头名字(IP地址或主机名)及接收通道(端口),通过码头把集装箱发出去[send()],腾出空间(close)。
三、TCP通信 1、ServerSocket 在开发TCP程序时,首先需要创建服务器端程序,其构造方法如下: ①ServerSocket() 使用该构造方法在创建ServerSocket对象时并没有绑定端口号,不能直接使用,还需要继续调用bind(SocketAddress endpoint)方法将其绑定到指定的端口上,才能正常使用。 ②ServerSocket(int port)【最常用】 使用用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上。 ③ServerSocket(int port,int backlog) backlog 参数用于指定在服务器忙时,可以与之保持连接请求的等待客户数量,如果没有指定这个参数默认为50 。 ④ServerSocket(int port,int backlog,InetAddress bindAddr) 指定了相关的IP地址,适用于计算机上有多块网卡和多个IP的情况。
2、Socket Socket类常用构造方法: ①Socket() 使用该构造方法在创建Socket对象时,并没指定IP地址和端口号,创建对象后还需调用connect(SocketAddress endpoint)方法,才能完成与指定服务器的连接,参数endpoint封装了IP地址和端口号。 ②Socket(String host,int port) 使用该构造方法在创建Socket对象时,根据参数去连接在指定IP地址和端口上运行的服务器程序,其中参数host接收的一个字符类型的IP地址。 ③Socket(InetAddress addres,int port) 与第二个构造方法类似,参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。
3、简单的TCP网络程序 1 import java.io.OutputStream; 2 import java.net.ServerSocket; 3 import java.net.Socket; 4 5 public class Example4 { 6 public static void main(String[] args) throws Exception { 7 new TCPServer().listen(); //创建TCPServer对象,并调用listen()方法 8 } 9 } 10 //TCP服务器端 11 class TCPServer{ 12 private static final int PORT= 7788;//定义一个端口号 13 14 public void listen() throws Exception{ //定义一个listen()方法,抛出一个异常 15 ServerSocket serverSocket = new ServerSocket(PORT);//创建ServerSocket对象 16 Socket client=serverSocket.accept(); //调用ServerSocket的accept()方法接收数据 17 OutputStream os = client.getOutputStream(); //获取客户端的输出流 18 System.out.println("开始与客户端交换数据"); 19 os.write(("Java欢迎你!").getBytes()); 20 Thread.sleep(5000); //模拟执行其他功能占用的时间 21 System.out.println("结束与客户端交互数据"); 22 os.close(); 23 client.close(); 24 } 25 } 登入後複製
1 import java.io.InputStream; 2 import java.net.InetAddress; 3 import java.net.Socket; 4 5 public class Example5 { 6 public static void main(String[] args) throws Exception{ 7 new TCPClient().connect();//创建TCPClient对象,并调用connect()方法 8 } 9 } 10 //TCP客户端 11 class TCPClient{ 12 private static final int PORT=7788;//服务端的端口号 13 public void connect() throws Exception{ 14 //创建一个Socket并连接到给出地址和端口号的计算机 15 Socket client = new Socket(InetAddress.getLocalHost(),PORT); 16 InputStream is = client.getInputStream(); //得到接收数据的流 17 byte[] buf = new byte[1024]; //定义1024个字节数组的缓冲区 18 int len=is.read(buf); //将数据读取到缓冲区中 19 System.out.println(new String(buf,0,len)); //将缓冲区中的数据输出 20 client.close(); //关闭Socket对象,释放资源 21 } 22 } 登入後複製
Example4 运行结果: 开始与客户端交换数据 结束与客户端交互数据 Example5 运行结果: Java欢迎你! 登入後複製
4、TCP案例——文件上传 实现图片上传到服务器的功能。 服务端程序: 1 import java.io.File; 2 import java.io.FileOutputStream; 3 import java.io.InputStream; 4 import java.io.OutputStream; 5 import java.net.ServerSocket; 6 import java.net.Socket; 7 8 public class Example7 { 9 public static void main(String[] args) throws Exception{ 10 ServerSocket serverSocket = new ServerSocket(10001);//创建ServerSocket对象 11 while (true){ 12 //调用accept()方法接收客户端请求,得到Socket对象 13 Socket s = serverSocket.accept(); 14 //每当和客户端建立Socket连接后,单独开启一个线程处理和客户端的交互 15 new Thread(new ServerThread(s)).start(); 16 } 17 } 18 } 19 class ServerThread implements Runnable{ 20 private Socket socket ; //持有一个Socket类型的属性 21 public ServerThread(Socket socket){ //构造方法中吧Socket对象作为实参传入 22 this.socket=socket; 23 } 24 25 @Override 26 public void run() { 27 String ip = socket.getInetAddress().getHostAddress(); //获取客户端的IP地址 28 int count =1; //上传图片个数 29 try{ 30 InputStream in = socket.getInputStream(); 31 //创建上传图片目录的File对象 32 File parentFile =new File("/Users/adims/Downloads/upload/"); 33 if (!parentFile.exists()){ //如果不存在,就创建这个目录 34 parentFile.mkdir(); 35 } 36 //把客户端的IP地址作为上传出文件的文件名 37 File file = new File(parentFile,ip+"("+count+").jpeg"); 38 while (file.exists()){ 39 //如果文件名存在,则把count++ 40 file=new File(parentFile,ip+"("+(count++)+").jpeg"); 41 } 42 //创建FileOutputStream对象 43 FileOutputStream fos = new FileOutputStream(file); 44 byte[] buf=new byte[1024]; //定义一个字节数组 45 int len=0; //定义一个int类型的变量len,初始值为0 46 while ((len=in.read(buf))!=-1){ //循环读取数据 47 fos.write(buf,0,len); 48 } 49 OutputStream out = socket.getOutputStream(); //获取服务端的输出流 50 out.write(("上传成功").getBytes()); //上传成功后向客户端写出"上传成功" 51 fos.close(); //关闭输出流对象 52 socket.close(); //关闭Socket对象 53 }catch (Exception e){ 54 throw new RuntimeException(e); 55 } 56 } 57 } 登入後複製 客户端程序: 1 import java.io.FileInputStream; 2 import java.io.InputStream; 3 import java.io.OutputStream; 4 import java.net.InetAddress; 5 import java.net.Socket; 6 7 public class Example8 { 8 public static void main(String[] args) throws Exception{ 9 Socket socket= new Socket(InetAddress.getLocalHost(),10001); //创建客户端Socket对象,指定IP地址和端口号 10 OutputStream out= socket.getOutputStream(); //获取Socket的输出流对象 11 //创建FileInputStream对象 12 FileInputStream fis = new FileInputStream("/Users/adims/Downloads/WechatIMG1.jpeg"); 13 byte[] buf =new byte[1024]; //定义一个字节数组 14 int len; //定义一个int类型的变量len 15 while ((len=fis.read(buf))!=-1){ //循环读取数据 16 out.write(buf,0,len); 17 } 18 socket.shutdownOutput(); //关闭客户端输出流 19 InputStream in = socket.getInputStream(); //获取Socket的输入流对象 20 byte[] bufMsg = new byte[1024]; //定义一个字节数组 21 int num =in.read(bufMsg); //接收服务端的信息 22 String Msg = new String(bufMsg,0,num); 23 System.out.println(Msg); 24 fis.close(); //关闭输入流对象 25 socket.close(); //关闭Socket对象 26 } 27 } 登入後複製 需注意:shutdownOutput()方法非常重要,因为服务器端程序在while循环中读取客户端发送的数据,当读取到-1时才会结束循环,如果客户端不调用shutdownOutput()方法关闭输出流,服务器端就不会读到-1,而会一直执行while循环,同时客户端服务器端的read(byte[])方法也是一个阻塞方法,这样客户端与服务器端进入一个“死锁”状态。 |
以上是Java之網路程式設計的使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!