java-网络通信

网络通信

  • java最初是作为一种控制家电的语言被开发出来的。当初设计该语言时,主旨之一是连接机器,而现在仍是如此。
  • java.net包让java能够通过网络进行通信。结合使用输入输出流,通过网络读写文件几乎和读写本地文件一样容易。
  • 要同网络上的系统进行通信,可以采用三种简单的方式:
    (1)在小程序中使用URL装载Web页和其他资源。
    (2)使用套接字类Socket和ServerSocket,它们建立到主机的标准套接字连接,并通过这种连接执行读写。
    (3)调用getInputStream(),该方法建立到URL的连接,并通过该连接来获取数据。

网络基本知识

  • 两台计算机间进行通讯需要以下三个条件:IP地址、协议、端口号
  • TCP/IP协议是目前世界上应用最为广泛的协议,是以TCP和IP为基础的不同层次上多个协议的集合,也成TCP/IP协议族、或TCP/IP协议栈
    TCP:Transmission Control Protocol 传输控制协议
    IP:Internet Protocol 互联网协议
  • TCP/IP五层模型
    应用层:HTTP、FTP、SMTP、Telnet等
    传输层:TCP ,UDP,UGP
    网络层: IP,ICMP,IGMP
    数据链路层:ARP,RARP
    物理层:网线、双绞线、网卡等
  • IP地址
        为实现网络中不同计算机之间的通信,每台计算机都必须有一个唯一的标识—IP地址。
  • 端口
        区分一台主机的多个不同应用程序,端口号范围为0-65535,其中0-1023位为系统保留。
    如:HTTP:80 FTP:21 Telnet:23
    IP地址+端口号组成了所谓的Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础
  • Socket套接字:
        网络上具有唯一标识的IP地址和端口组合在一起才能构成唯一能识别的标识符套接字。
       Socket原理机制:
         通信的两端都有Socket
         网络通信其实就是Socket间的通信
         数据在两个Socket间通过IO传输
  • Java中的网络支持
         针对网络通信的不同层次,Java提供了不同的API,其提供的网络功能有四大类:
         InetAddress:用于标识网络上的硬件资源,主要是IP地址
         URL:统一资源定位符,通过URL可以直接读取或写入网络上的数据
         Sockets:使用TCP协议实现的网络通信Socket相关的类
         Datagram:使用UDP协议,将数据保存在用户数据报中,通过网络进行通信。

InetAdress

Java提供了InetAddress类来代表IP地址,实现对IP地址的封装。

获得本机InetAddress实例
			InetAddress address = InetAddress.getLocalHost();
			System.out.println(address.getHostName());
			System.out.println(address.getHostAddress());
获得其他主机InetAddress实例
			InetAddress address2 =InetAddress.getByName("其他主机名");
			InetAddress address3 =InetAddress.getByName("IP地址");

URL

url是统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

构造函数
public URL(String spec)
			spec - 将作为 URL 解析的 String。 
public URL(String protocol, String host, int port,String file,URLStreamHandler handler)
			protocol - 要使用的协议名称。
			host - 主机名称。
			port - 主机端口号。
			file - 主机上的文件
			handler - URL 的流处理程序。 
不一定使用全部参数。

http://www.baidu.com
		http://  :代表超文本传输协议,通知microsoft.com服务器显示Web页,通常不用输入;
		www  :代表一个Web(万维网)服务器;
		baidu :为域名主体
		.com  :com为顶级域名,com是company的缩写,是最常用的顶级域名,表示商业网站。
		常见的还有net,cn等
URL的常用方法
try {
			URL url = new URL("https://mp.csdn.net/mdeditor/84201258");
			System.out.println(url.getProtocol());//获取协议
			System.out.println(url.getHost());//获取主机
			System.out.println(url.getPort());//获取端口,如果未设置端口号,则返回 -1
			System.out.println(url.getFile());//获取此 URL 的文件名。
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

       使用URL读取网页内,通过URL对象的openStream()方法可以得到指定资源的输入流,通过流能够读取或访问网页上的资源

  try {
		URL url = new URL("http://www.baidu.com");
		StringBuffer sBuffer =new StringBuffer();
		InputStreamReader  iReader =new InputStreamReader(url.openStream(),"UTF-8");
		BufferedReader bReader =new BufferedReader(iReader);
		String data ;
		while((data=bReader.readLine())!=null){
			sBuffer.append(data);
		};
		System.out.println(sBuffer.toString());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

Tcp编程

1、TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低。
2、Java中基于TCP协议实现网络通信的类
            客户端的Socket类
             服务器端的ServerSocket类
通信模型
3、Socket通信的步骤
    ① 创建ServerSocket和Socket
    ② 打开连接到Socket的输入/输出流
    ③ 按照协议对Socket进行读/写操作
    ④ 关闭输入输出流、关闭Socket
4、服务器端:
     ① 创建ServerSocket对象,绑定监听端口
     ② 通过accept()方法监听客户端请求
     ③ 连接建立后,通过输入流读取客户端发送的请求信息
     ④ 通过输出流向客户端发送乡音信息
     ⑤ 关闭相关资源

客户端方法介绍

构造方法概述
Socket() 
          通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port) 
          创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
			address - IP 地址。
			port - 端口号。
普通方法概述
void connect(SocketAddress endpoint) 
          将此套接字连接到服务器。 
 void setSoTimeout(int timeout) 
         启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位。 当时间超过timeout毫秒
         时,将触发InterruptedIOException异常,因此可以在try-catch块关闭套接字或再次
         读写数据。
 boolean isConnected() 
          返回套接字的连接状态。 

注意:
(1)创建套接字时,应设置其超时值, 当时间超过超时值时,将触发InterruptedIOException异常,因此可以在try-catch块关闭套接字或再次读写数据。如果没有设置,它可能一直等待下去。
(2)通常将网络操作放在单独的线程中,并让它和程序的其他部分分开运行。

服务器端方法概述

构造函数
ServerSocket() 
          创建非绑定服务器套接字。 
ServerSocket(int port) 
          创建绑定到特定端口的服务器套接字。 
普通方法
 Socket accept() 
          侦听并接受到此套接字的连接。 
 void bind(SocketAddress endpoint) 
          将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 
 InetAddress getInetAddress() 
          返回此服务器套接字的本地地址。 
void setSoTimeout(int timeout) 
          通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
boolean isBound() 
          返回 ServerSocket 的绑定状态。  

(1)创建服务器端时,要绑定端口号,可以在构造函数或者利用bind()函数绑定,服务器端监听这个端口,客户端通过IP地址和这个端口连接到服务器上。
(2)端口0-1023的用途由Internet地址分配机构使用。
(3)要先运行服务器端,在运行客户端。
实例:
   创建客户端和服务端,客户端连接到服务器时,服务端发送当前时间,并断开连接,客户端显示出来时间。

客户端结果
服务器端代码

package CommDemo;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import javax.xml.crypto.Data;

public class ServerDemo  extends Thread{
	private ServerSocket myServer =null;
	 public ServerDemo(int port){
		  try {
					myServer =new ServerSocket(port);
					System.out.println("服务器开始运行");
				} catch (IOException e) {
					e.printStackTrace();
					System.err.println("could not ....");
				}
	 }
	 
	 public void run(){
	     //对客户端的连接要放在多线程里,否则一直等待连接。
		 Socket  mySocket =null;
		  while(true){
		   //死循环,不断检测有无连接的客户端
			   try {
				mySocket =myServer.accept();
				System.out.println("客户端连接成功");
				BufferedOutputStream bOutputStream =new    	
				BufferedOutputStream(mySocket.getOutputStream());
				Date date = new Date();
				PrintWriter pWriter =new PrintWriter(bOutputStream,false);
				pWriter.println(date);
				pWriter.flush();
				pWriter.close();
				bOutputStream.close();
				mySocket.close();
			
			} catch (IOException e) {
				e.printStackTrace();
				System.err.println("无法连接到客户端");
				
			}
		  }
	 }
	public static void main(String[] args) {
		ServerDemo  myServerDemo =new ServerDemo(6666);
		myServerDemo.start();
	}
}

客户端程序

package CommDemo;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class ClientDemo extends Thread implements ActionListener {
  
	 private Socket mySocket = null;
	 private   JButton connect =new JButton("连接服务器");
      private  JButton disconnect =new JButton("断开服务器");
      BufferedInputStream bInputStream =null;
      JTextArea myArea =null;
	 public ClientDemo(){
			 //初始化界面
			   JFrame frame = new JFrame("客户端");
			   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		      myArea=new JTextArea("",5,10);
		       frame.getContentPane().add(myArea, "Center");
		       JPanel panel =new JPanel();
		       panel.setLayout(new FlowLayout());
		       connect.addActionListener(this);
		       disconnect.addActionListener(this);
		       panel.add(connect);
		       panel.add(disconnect);
		       frame.getContentPane().add(panel, "South");
		       frame.pack();
		       frame.setVisible(true); 
	 }
	public static void main(String[] args) {
		ClientDemo myClientDemo =new ClientDemo();  
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		  if(e.getSource()==connect){
				try {
					StringBuffer sBuffer = new StringBuffer();
					mySocket = new Socket("127.0.0.1", 6666);//连接本地IP的6666端口
					mySocket.setSoTimeout(10000);//设置超时值
					bInputStream=new BufferedInputStream(mySocket.getInputStream());
					   int data =-1;
						while((data=bInputStream.read())!=-1){
						  sBuffer.append((char)data);
					   }
					myArea.setText(sBuffer.toString());
				} catch (IOException e1) {
					e1.printStackTrace();
				}	
		  }else if(e.getSource()==disconnect){
				try {
					myArea.setText("已断开连接");
					bInputStream.close();
					mySocket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}		
		  }
	}
}

UDP编程

  • UDP协议(用户数据报协议)是无连接的、不可靠的、无序的,速度快,进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去
  • UDP通信中使用的两个类:
    DatagramPacket类:表示数据报包
    DatagramSocket类:进行端到端通信的类
  • 使用UDP进行编程的步骤
    客户端:
    (1)使用DatagramPacket包装要发送的数据。
    DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。address是要发送的服务器的ip地址,port是服务器的端口号。
    (2)建立DatagramSocket对象,通过方法DatagramSocket(int port)
    创建数据报套接字并将其绑定到本地主机上的指定端口。这里的port是客户端的端口号,服务器可以根据客户端的IP和端口,向客户端反馈信息。
    (3) void send(DatagramPacket p)
    从此套接字发送数据报包 。

服务器端
(1)建立DatagramSocket对象,通过方法DatagramSocket(int port)
创建数据报套接字并将其绑定到本地主机上的指定端口。
(2)DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。
(3)使用DatagramSocket对象的 void receive(DatagramPacket p)方法从此套接字接收数据报包。
(4)将此数据包转换成适当的数据形式
(5)通过int getPort()返回客户端的端口。InetAddress getInetAddress()返回客户端的IP地址。 从而服务端也可向客户端发送数据包,发送步骤等同于客户端发送数据包。

示例
客户端向服务器端发送当前时间,服务器端显示收到的时间。
运行结果
运行结果
上面是两次客户端发来结果时,服务器端的显示

服务器端

package CommDemo;

import java.awt.BorderLayout;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import javax.swing.JFrame;
import javax.swing.JTextArea;

public class UdpServerDemo extends JFrame implements Runnable{
	 private DatagramSocket serverSocket = null;
	 private DatagramPacket receivePacket =null;
	 private byte bytes[];
	 JTextArea textArea =null;
	public UdpServerDemo(int port){
		//建立界面
		super("服务器端");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new BorderLayout());
		textArea=new JTextArea("",10,50);
		getContentPane().add(textArea, "Center");
       pack();
		setVisible(true);
		
		try {
			System.out.println("服务器正在运行");
			serverSocket =new DatagramSocket(port);
			bytes =new byte[1024];  
			receivePacket =new DatagramPacket(bytes, bytes.length);	
			
		} catch (SocketException e) {
		   System.out.println("couldnot");
			e.printStackTrace();
		}
	}
	public  void run(){
		while(true){
			 try {
					serverSocket.receive(receivePacket);
					System.out.println("客户端已连接");
					Object object  =bytesToObject(receivePacket.getData());
					textArea.append("客户端发来:"+object .toString()+"\n");
				} catch (IOException e) {
					System.out.println("连接失败");
					e.printStackTrace();
				}
		}	 
	}
	//将字节数组转换成对象
	public Object bytesToObject(byte bytes[]){ 
	      Object obj =null;
		  try {
		   ByteArrayInputStream bArrayInputStream =new ByteArrayInputStream(bytes);
			  ObjectInputStream objectInputStream =new 
			  ObjectInputStream(bArrayInputStream);
	          obj =objectInputStream.readObject();
		  } catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return obj;  
	}
	public static void main(String[] args) {
		
		
		UdpServerDemo myServerDemo =new UdpServerDemo(6667);
		Thread serverThread = new Thread(myServerDemo);
		serverThread.start();
		
	}
}

客户端

package CommDemo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Date;

import javax.swing.JFrame;

public class UdpClientDemo {

	DatagramSocket  clientSocket =null;
	DatagramPacket  clientPacket =null;
	byte bytes [];
	InetAddress sendAddress =null;
	public UdpClientDemo(int port){
		try {
			clientSocket =new DatagramSocket(port);
			sendAddress = InetAddress.getByName("127.0.0.1");
			bytes=new byte[1024];
			bytes = ObjectToBytes(new Date());
			clientPacket =new DatagramPacket(bytes,bytes.length,sendAddress,6667);
			clientSocket.send(clientPacket);
			clientSocket.close();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
		
			e.printStackTrace();
		}
	}
	public byte[] ObjectToBytes(Object obj){
		   ByteArrayOutputStream bArrayOutputStream =new ByteArrayOutputStream();
		   try {
			ObjectOutputStream objectOutputStream =new ObjectOutputStream(bArrayOutputStream);
		   objectOutputStream.writeObject(obj);
		   bytes =bArrayOutputStream.toByteArray();
		   } catch (IOException e) {
			e.printStackTrace();
		}
		  return  bArrayOutputStream.toByteArray();
       
	}
	
	public static void main(String[] args) {
	UdpClientDemo myClientDemo = new UdpClientDemo(6668);
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值