毕向东之网络编程Tcp与UDP
/*网络编程:通讯三要素:IP地址,端口号,传输协议 IP地址不易记忆,可用主机名(localhost)<相当于酒店名,也相当于电脑> 端口号<相当于酒店里的房间号,电脑上某个软件> 传输协议:UDP(如发消息,不需要对方连接),TCP(如打电话,必须要对方连接) UDP特点:将数据封装成包,每个包的大小限制在64K内,不需要建立连接,是不可靠协议,但速度快 TCP特点:建立连接,形成传输数据的通道, 在连接中进行大数据传输,通过三次握手完成连接,是可靠协议(叫<在吗>,应<在>,回<知道了>) 必须建立连接,效率会稍低 Socket(插座):就是为网络服务提供的一种机制,通信的两端都有Socket(相当于码头,两台电脑传输的桥梁) 网络通信其实就是Socket之间的通信 那么UDP的Socket服务怎么建立呢? DatagramSocket:此类表示用来发送和接收数据报包的套接字。(用于接收发送) DatagramPacket:此类表示数据报包, 数据报包用来实现无连接包投递服务(用于数据打包,包裹发到哪去必须给出IP和端口) 需求:通过UDP传输方式,将一段文字数据发送出去。 步骤:1.建立UDPSocket服务。2.提供数据,并将数据打包。 3.通过Socket服务的发送功能将数据包发出去。4.关闭资源 */ import java.net.*; class Udpsend{//发送 public static void main(String[] args)throws Exception{ InetAddress inetd=InetAddress.getLocalHost(); System.out.println(inetd.getHostAddress());//获取主机地址 System.out.println(inetd.getHostName());//获取主机名称 DatagramSocket ds=new DatagramSocket(888);//建立UDPSocket服务,没有定义服务站端口名系统会自动添加一个 byte[] buf="数据来了".getBytes(); //提供数据,并将数据打包。确定发送到的IP和端口名 DatagramPacket ap=new DatagramPacket(buf,buf.length,InetAddress.getByName(inetd.getHostName()),1720); ds.send(ap);//将数据包发出去 ds.close();//关闭资源 } } //用于接收发出端口发来的数据 class Udpreceive{//接收 public static void main(String[] args)throws Exception{ //定义Socket服务接收 接收哪个发来的呢?所以要定义服务站的端口名且与发送端一致才能接收到 DatagramSocket ds=new DatagramSocket(1720);//端口为1720,端口知道绑定一个Socket //定义字节数组存放数据 byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf,buf.length); //通过服务的receive方法将收到的数据存入数据包中 ds.receive(dp);//阻塞式方法,没数据就等 //通过数据包的方式获取其中的数据 int len=dp.getLength();//数据的长度 String data=new String(dp.getData(),0,len);//获取接收的数据 int port=dp.getPort();//获取发送端的端口号 String ip=dp.getAddress().getHostAddress();//返回 IP地址字符串 System.out.println(ip+"---"+data+"---"+port); ds.close();//关闭服务站 } }
//阻塞式方法 import java.net.*; import java.io.*; class Udpsend2{//发送 public static void main(String[] args) throws Exception{ DatagramSocket ds=new DatagramSocket(888); BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String line; String ip=InetAddress.getLocalHost().getHostName(); while((line=br.readLine())!=null){ if(line.equals("886")) break; byte[] arr=line.getBytes();//变为字节数组发送出去(发送就要指明地点和数据) DatagramPacket dp=new DatagramPacket(arr,arr.length,InetAddress.getByName(ip),1000); ds.send(dp); } ds.close(); } } class Udpreceive2{//接收 public static void main(String[] args)throws Exception{ DatagramSocket ds=new DatagramSocket(1000); while(true){//不停的接收 byte[] arr=new byte[1024]; DatagramPacket dp=new DatagramPacket(arr,arr.length);//用来存储数据 ds.receive(dp);//接收数据 byte[] data=dp.getData();//只有一部分是接收到的数据 String textdata=new String(data,0,dp.getLength());//将数组arr一部分转换为字符串数据 System.out.println(dp.getAddress()+"--"+dp.getPort()+"--:"+textdata); } } }
/*需求:自己电脑既能接收数据又能发送数据 127.0.0.1为我电脑的IP .1改为.255代表播放频段,局域网中只要开着端口就能就收到数据 */ import java.net.*; import java.io.*; public class Test3 { public static void main(String[] args) throws Exception{ Thread t1=new Thread(new Receive(new DatagramSocket(101))); Thread t2=new Thread(new Send(new DatagramSocket(88))); t1.start();//先走接收 t2.start(); } } class Send implements Runnable{//发送 private DatagramSocket sd; public Send(DatagramSocket sd){ this.sd=sd; } public void run(){ BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String line; try{ while((line=br.readLine())!=null){ if(line.equals("886")) break; byte[] arr=line.getBytes(); String ip=InetAddress.getLocalHost().getHostName(); DatagramPacket dp=new DatagramPacket(arr,arr.length,InetAddress.getByName("127.0.0.255"),101); sd.send(dp); } }catch(Exception e){ throw new RuntimeException("发送失败"); } } } class Receive implements Runnable{//接收 private DatagramSocket ds; public Receive(DatagramSocket ds){ this.ds=ds; } public void run(){ try{ byte[] arr=new byte[1024]; DatagramPacket dp=new DatagramPacket(arr,arr.length); while(true){ ds.receive(dp); byte[] tata=dp.getData(); String text=new String(tata,0,dp.getLength()); System.out.println(dp.getAddress()+"-:"+text); } }catch(Exception e){ throw new RuntimeException("接收失败"); } } }
/* TCP传输包括:由客户端(Socket)和服务端(ServerSocket) 连接后通过Socket中的IO流进行数据的传输 需求:客服端向服务端发送一文本信息,服务端接收到后向客服端回一信息 此题注意点:当读数据用readLine方法时,读完一行会继续读,使得程序一直读回写不了信息 因为readLine即是阻塞式方法,结束标志必须是没有数据,所以结束不了 */ import java.net.*; import java.io.*; class TcpServer{//伺候客户的服务端 public static void main(String[] args)throws Exception{ //创建服务端,且指明接收的端口号 ServerSocket ss=new ServerSocket(10000); //获取连接过来的客服端对象 Socket s=ss.accept();//阻塞式方法,等待连接 String ip=s.getInetAddress().getHostName();//获取连过来的IP System.out.println(ip+"连上了"); //获取输入输出流 OutputStream out=s.getOutputStream(); BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(out)); InputStream in=s.getInputStream(); BufferedReader bufr=new BufferedReader(new InputStreamReader(in)); //读客户端发来的数据 char[] arr=new char[1024]; int len=bufr.read(arr); System.out.println(new String(arr,0,len)); //向客户端发数据 bufw.write("在"); bufw.newLine();//因为客户端的读数据是一行行读,如果没有换行标记会一直读,因为没有结束标记 bufw.flush(); } } class TcpSocket{//客户端 public static void main(String[] args)throws Exception{ //创建客户端,且指明需要连接的服务端和端口 Socket s=new Socket("127.0.0.1",10000); OutputStream out=s.getOutputStream(); BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(out)); InputStream in=s.getInputStream(); BufferedReader bufr=new BufferedReader(new InputStreamReader(in)); //客户端发送数据 bufw.write("服务端,在吗?"); bufw.newLine(); bufw.flush(); //客户端接收服务端发来的数据 char[] arr=new char[1024]; int len=bufr.read(arr); System.out.println(new String(arr,0,len)); s.close(); } }
/*需求:建立一个文本转换服务器,客服端给服务端发送文本,服务端会将文本转换成大写再返回给客服端 容易出现的问题:客服端和服务端都在莫名的等待 因为客服端和服务端都有阻塞式方法,这些方法没有读到结束标记,那么就一直等待,导致两端都在等待 */ import java.net.*; import java.io.*; class TCPSocket2{//客服端 public static void main(String[] args)throws Exception{ Socket s=new Socket(InetAddress.getLocalHost().getHostAddress(),100); BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); String line; while((line=in.readLine())!=null){//-1 或换行标记时才结束循环 if(line.equals("over")) break; bufw.write(line);//将键盘录入数据发送给服务端 bufw.newLine();//为服务端提高数据结束标记 bufw.flush();//将数据刷出去 String str=bufr.readLine();//读客服端发来的数据 System.out.println(str); } s.close();//当关闭时,客服端读方法会有个结束标记-1 in.close(); } } class TCPServer2{//服务端 public static void main(String[] args)throws Exception{ ServerSocket ss=new ServerSocket(100); Socket s=ss.accept(); System.out.println(s.getInetAddress().getHostAddress()+"连上来了"); BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); String str; while((str=bufr.readLine())!=null){//接收客服端发来的数据,当客服端关闭后读数据会有结束标记 bufw.write(str.toUpperCase());//转换为大写发出去 bufw.newLine();//为接受端提供读结束标记 bufw.flush(); } } }
/*需求:实现文件的发送 */ import java.io.*; import java.net.*; class TcpSocket6{ public static void main(String[] args)throws Exception{ Socket s=new Socket(InetAddress.getLocalHost().getHostAddress(),100); BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter ps=new PrintWriter(s.getOutputStream(),true);//自动刷新且换行 BufferedReader filer=new BufferedReader(new FileReader("E:\\学习文件\\fuzhi.java")); String line; while((line=filer.readLine())!=null){//读文本有结束标记 ps.println(line);//将读到的数据发送给服务端 }//避免出现双方等待的现象, s.shutdownOutput();//关闭写,相当于给服务端的readLine方法一个结束的标记(-1) String str=bufr.readLine();//读服务端发来的信息 System.out.println(str); s.close();filer.close(); } } class TcpServer6{ public static void main(String[] args)throws Exception{ ServerSocket ss=new ServerSocket(100); Socket s=ss.accept(); System.out.println(s.getInetAddress().getHostAddress()+"..连接上了"); BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); PrintWriter pw=new PrintWriter(s.getOutputStream(),true); PrintWriter filew=new PrintWriter(new FileWriter("E:\\学习文件\\1.txt")); String line; while((line=bufr.readLine())!=null){//读发来的数据,结束标记为shutdownOutput() filew.println(line); } pw.println("传输成功"); filew.close(); } }
/*需求:实现多人向服务端发送图片 因为服务端要处理多个对象的连接,所以必须要用到线程 */ import java.io.*; import java.net.*; public class Test7 { public static void main(String[] args)throws Exception{ ServerSocket ss=new ServerSocket(100); while(true){//服务器原理 Socket s=ss.accept(); new Thread(new TcpServer7(s)).start(); } } } class TcpServer7 implements Runnable{ private Socket ss;//服务端获取的连接对象 public TcpServer7(Socket ss){ this.ss=ss; } public void run(){ try{ int count=1; BufferedInputStream bufi=new BufferedInputStream(ss.getInputStream()); BufferedOutputStream bufo=new BufferedOutputStream(ss.getOutputStream()); String ip=ss.getInetAddress().getHostAddress(); File file=new File("F:\\图片\\"+ip+"("+count+")"+".jpg"); while(file.exists()){ count++; file=new File("F:\\图片\\"+ip+"("+count+")"+".jpg"); } BufferedOutputStream fileout=new BufferedOutputStream(new FileOutputStream(file)); byte[] arr=new byte[1024]; int len; while((len=bufi.read(arr))!=-1){ fileout.write(arr, 0, len); fileout.flush(); } bufo.write(new String("传输成功").getBytes()); bufo.flush(); ss.shutdownOutput(); }catch(Exception e){ } } } class TcpSocket7{//客服 public static void main(String[] args)throws Exception{ File file=new File(args[0]);//编译时传args[0] BufferedInputStream fileo=new BufferedInputStream(new FileInputStream(file));//读取指定目录 Socket s=new Socket("127.0.0.1",100); BufferedInputStream bufi=new BufferedInputStream(s.getInputStream()); BufferedOutputStream bufo=new BufferedOutputStream(s.getOutputStream()); byte[] arr=new byte[1024]; int len; while((len=fileo.read(arr))!=-1){ bufo.write(arr,0,len); bufo.flush(); } s.shutdownOutput();//写结束 len=bufi.read(arr); System.out.println(new String(arr,0,len)); s.close(); fileo.close(); } }
/*模拟IE浏览器—服务器 */ import java.io.*; import java.net.*; public class Test8 {//模拟服务端 public static void main(String[] args)throws Exception { ServerSocket ss=new ServerSocket(101); Socket s=ss.accept(); System.out.println(s.getInetAddress().getHostAddress()+"...连接成功"); BufferedInputStream bufi=new BufferedInputStream(s.getInputStream()); byte[] arr=new byte[1024]; //int len=bufi.read(arr);//获取浏览器发来的信息 //System.out.println(new String(arr,0,len)); /*接收到的浏览器发来的数据 http://127.0.0.1:100/Test1.java 主机端口的资源 GET /Test1.java HTTP/1.1 http代表协议 Accept: text/html, application/xhtml+xml, 代表能接收的类型 Accept-Language: zh-CN 简体中文 User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) UA-CPU: AMD64 用户信息 Accept-Encoding: gzip, deflate 支持的封装形式(解压) Host: 127.0.0.1:100 Connection: Keep-Alive 连接保持存活 */ PrintStream ps=new PrintStream(s.getOutputStream(),true); BufferedReader bufr=new BufferedReader(new FileReader("F:\\QQ文件\\my.html")); String str; while((str=bufr.readLine())!=null){ ps.println(str);//向浏览器发送数据 } s.shutdownOutput(); s.close(); ss.close(); } } class URLSocket{//客服端 public static void main(String[] args)throws Exception{ URL u=new URL("http://127.0.0.1:101/my.html");//连接资源封装成对象 URLConnection con=u.openConnection();//URL所引用的远程对象的连接。 System.out.println(con); InputStream in=con.getInputStream(); } }