概述
如果两台计算机要通讯,那么它必须满足以下3点:
1、每台电脑要有唯一标识,即是IP地址。
2、用于通讯的应用程序也要有唯一标识,即是端口。
3、通讯时要遵循一定的规则,成为协议。国际组织定义了通用协议TCP/IP协议。
IPv4地址是四段,为了解决IP地址不够用的问题出现了IPv6是六段,不仅支持数字还支持字母。
端口取值:0~65535 0~1024一般情况下被系统的程序保留
网络参考模型
TCP和UDP
UDP面向无连接,比如邮局寄信时只需要把信要寄往的地址写明确即可,而不需要考虑收信人知道或不知道,是否在。
特点:
1、将数据及源和目的封装成数据包中,不需要建立连接。
2、每个数据包的大小限制在64内。
3、因无连接,是不靠协议,容易丢包。
4、不需要建立连接,传送数据快。
TCP面向相连接 要求对方必须在,比如打电话的流程。这里是利用三次握手的原理
特点:
1、建立连接形成传输数据的通道。
2、在连接中进行大量的数据传输。
3、通过三次握手完成连接,是可靠协议。
4、必须建立连接,传输效率稍低。
Socket
它是为网络服务提供的一种机制;通信的两端都有socket;网络通信其实就是socket间的通信;数据通过IO流进行传输。相当于船靠岸的港口。
不同类型的协议传输需要不同类型的Scoket进行传输。
UDP传输用到DatagramSocket,以下是一个UDP传输的示例:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; /* * 示例:模仿UDP传输的发送端 键盘输入 * */ public class UdpSend1 { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub //1、创建服务 DatagramSocket ds=new DatagramSocket(); //2、创建所需发送的数据包 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String line=null; while((line=br.readLine())!=null){ if("o".equals(line))break; byte[] buf=line.getBytes(); InetAddress i=InetAddress.getByName("172.25.218.3"); DatagramPacket dp=new DatagramPacket(buf, buf.length,i,10001); //3、发送数据包 ds.send(dp); System.out.println("send data......"); } //4、关闭流 ds.close(); } } import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; //UDP传输的接收端 public class UdpRecive1 { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub //创建端口为10001的sokect服务 DatagramSocket ds=new DatagramSocket(10001); while(true){ //接受数据包 byte[] buf=new byte[1024]; DatagramPacket p=new DatagramPacket(buf, buf.length); System.out.println("wait data....."); ds.receive(p); System.out.println("shoudao data....."); String ip=p.getAddress().getHostAddress(); String data=new String(p.getData(),0,p.getLength() ); int port=p.getPort(); System.out.println("ip:"+ip); System.out.println("data:"+data); System.out.println("port:"+port); } } }
TCP传输 Socket
面向连接传输时有两个端:客户端(Socket)和服务端(ServerSocket)
多个客户端向服务器发送数据传输时,服务器端可以获取到这个客户端的socket,进而可以得到此客户端和服务器端通信的流对象进行通信,就好比两个人打电话,电话有话筒和听筒,两边可通过这个进行交流。
下面是一个简单的例子:在客户端通过键盘向服务器端发送文本数据,服务器端接收到数据后打印到控制台上,并把收到的数据转成大写发给客户端,客户端把收到的数据也打印到控制台上。
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; public class TcpClinet { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub Socket s=new Socket("172.25.218.3",10003); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); //定义一个socket读去流,读取服务端返回的大写的信息 BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); String line=null; while((line=br.readLine())!=null){ if("886".equals(line)) break; bw.write(line); bw.newLine(); bw.flush(); String lines=bufr.readLine(); System.out.println("server:"+lines); } br.close(); s.close(); } } import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class serverSocket { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ServerSocket ss=new ServerSocket(10003); Socket s=ss.accept(); String ip=s.getInetAddress().getHostAddress(); System.out.println("ip:"+ip+"connected...."); BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream())); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); String line=null; while((line=br.readLine())!=null){ System.out.println(line); bw.write(line.toUpperCase()); bw.newLine(); bw.flush(); } ss.close(); s.close(); } }
第二个示例:图片的上传
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.net.Socket; //客户端上传图片到服务器 public class TcpClinet2 { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub Socket s=new Socket("172.25.218.3",10006); BufferedInputStream bi=new BufferedInputStream(new FileInputStream(new File("D:\静静.jpg"))); BufferedOutputStream bo=new BufferedOutputStream(s.getOutputStream()); byte[] buf=new byte[1024]; int len=0; while((len=bi.read(buf))!=-1){ bo.write(buf, 0, len); } s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入一个结束标记-1 System.out.println("文件上传成功!!"); s.close(); } } import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; //思考:服务器需要供多个客户端同时上传文件,此时服务器应开启多线程,以达到并发访问。 class server implements Runnable{ private Socket s; server(Socket s){ this.s=s; } @Override public void run() { // TODO Auto-generated method stub try{ System.out.println("ip:"+s.getInetAddress().getHostAddress()); //服务器读取socket的输入流 BufferedInputStream bi=new BufferedInputStream(s.getInputStream()); //创建要写出到某个文件的流。 BufferedOutputStream bo=new BufferedOutputStream(new FileOutputStream(new File("D:\jing.jpg"))); byte[] buf=new byte[1024]; int len=0; while((len=bi.read(buf))!=-1){ bo.write(buf,0,len); } System.out.println("已成功接收到文件"); s.close(); } catch(Exception e){ throw new RuntimeException("上传失败!!"); } } } class serverSocket2 { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ServerSocket ss=new ServerSocket(10006); while(true){ Socket s=ss.accept(); new Thread(new server(s)).start(); } //ss.close(); } }
经过上述几个例子可以发现其实网络间数据的传输也就是流的写入写出。