java基础—10.网络编程TCP/UDP

来源:互联网 发布:linux tcp发送窗口 编辑:程序博客网 时间:2024/06/05 18:44

一、概念及理解

网络通信是指数据从一个IP地址,发送到另一个IP地址。根据OSI七层通信模型,发送数据时不断封装,接收过程不断解封装,如下:

二、基础知识

|--网络模型
网络参考模型有OSI参考模型,在OSI基础上提出的TCP/IP模型,如下:
|--网络通信要素
|--IP
网络中设备的标识不易记忆,可用主机名本地回环地址:127.0.0.1 主机名:localhost对应的Java类是:InetAddress类|--端口号用于标识进程的逻辑地址,不同进程的标识有效端口:0~65535,其中0~1024系统使用或保留端口|--传输协议在TCP/IP模型中的传输层中,广泛应用的有两个协议,分别是:UDP  、TCP,比较如下:TCP• 建立连接,形成传输数据通道• 进行在数据传输• 三次握手,连接可靠• 建立连接时,效率较低UDP• 将数据封装成数据包,不需建立连接• 每个数据64K以内• 因无连接,是不可靠协议,容易丢包• 不需连接,速度快,效率高
|--Socket         网络编程,其实上就是Socket编程,Socket就是为网络服务提供的一种机制,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。不同的协议,建立Socket方法不一样,Socket的通信模型如下:
|--URL统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
|--openStream() 
打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。|--openConnection()           返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。|--getQuery()           获取此 URL 的查询部分。|--getPath()           获取此 URL 的路径部分。|--getFile()           获取此 URL 的文件名。|--域名解析域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站一种服务。说得简单点就是将好记的域名解析成IP,服务由DNS服务器完成,是把域名解析到一个IP地址,然后在此IP地址的主机上将一个子目录与域名绑定。

三、UDP

UDP的数据传送最明显的特点是,只管传,不管接没接。在Java中的UDP网络编程的套路固定,分为发送端和接收端:
|--DatagramPacket类用于接收套接字中的数据|--DatagramSocket类用于发送接收数据
|--发送端:
• 建立updsocket服务• 提供数据,并将数据封闭到数据包中• 通过Socket服务的发送功能,将数据包发送出去;• 关闭资源
//发送数据端public class UdpSend1 {public static void main(String[] args)throws Exception {//建立套接字DatagramSocket ds = new DatagramSocket();//接收键盘输入的数据BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String lin;//重复性的输入数据,读取数据while((lin=br.readLine())!=null){//定义数组byte[] buf = lin.getBytes();//建立数据包,把Buf中的数据读出存放,并往规定的主机和端口上发送DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8888);ds.send(dp);//当输入over时,发送端程序if("over".equals(lin))break;}//关流ds.close();br.close();}}
|--接收端:• 定义updsocket服务• 定义一个数据包,因为要存储接收到的字节数据• 通过socket服务的receive方法将收到的数据存入已定义好的数据包中• 通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上• 关闭资源
//UDP的接收数据端public class UdpRece1 {public static void main(String[] args)throws Exception {//建立固定端口8888的套接字DatagramSocket ds = new DatagramSocket(8888);while(true){//建立数据接收数据byte[] buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf,buf.length);//System.out.println("等待接收");//接收数据ds.receive(dp);//获取发送端的IP信息String ip = dp.getAddress().getHostAddress();String data = new String (dp.getData(),0,dp.getLength());int port = dp.getPort();//打印发送端口信息System.out.println(ip + "::"+"::"+port+data);//识别发送端的数据,如果有over,则终止程序if(data.equals("over"))break;}ds.close();}}

四、TCP

TCP的特点是传输可靠,并且不在套接字Socket建立时,就要指定端口,其中编程步骤如下:
|--客户端
• 创建客户端的Socket服务,指定目的主机和端口• 为了发送数据,应该获取Socket流中的输出流
public class TcpClient {public static void main(String[] args)throws Exception {//1. 建立套接字Socket,并指定端口Socket  s = new Socket("127.0.0.1",10002);//2. 获取套接字的输出流OutputStream,进行操作OutputStream os = s.getOutputStream();os.write("I'm coming ! hahahaha,lol^_^".getBytes());//3.关资源,只要关Socket就可以 了s.close();}}
|--服务端• 建立服务端口的Socket服务。ServerSocket();并监听这个端口• 获取连接过来的客户端对象;accept()—阻塞式方法• 建立服务端的Socket对象,与客户端对接• 关闭资源(可选)
public class TcpServer {public static void main(String[] args)throws Exception {//1.建立服务端口套接字ServerSocketServerSocket ss = new ServerSocket(10002);//2.建立连接套接字Socket,与客户端对接Socket  s = ss.accept();//3.让连接套接字Socket获取输入流,并操作byte[] buf = new byte[1024];InputStream  is = s.getInputStream();int len = is.read(buf);System.out.println(new String(buf,0,len));//4.关闭资源s.close();ss.close();}}

五、网络编程练习

|--并发上传图片
|--服务端
public class DemoPicServer {public static void main(String[] args) throws Exception {@SuppressWarnings("resource")//服务器没关流,进行声明//声明服务器的端口ServerSocket ss = new ServerSocket(10007);//等待多个客户端的连接while(true){//等待连接Socket s = ss.accept();//建立线程,并开启线程PicThread pt =new PicThread(s);new Thread(pt).start();}}}class PicThread implements Runnable{Socket s;//构造函数PicThread(Socket s){this.s = s;}//实现的run方法public void run() {try {//文件存在时,文件名的自己增变量int count=1;String ip = s.getInetAddress().getHostAddress();//制定文件名File f =new File("G:\\test\\"+ip+"("+count+")"+".jpg");while(f.exists())f =new File("G:\\test\\"+ip+"("+(count++)+")"+".jpg");//文件写流FileOutputStream fos = new FileOutputStream(f); //建立套接字的读取流InputStream is = s.getInputStream();byte[] buf = new byte[1024];int len;//套接字的输入流,全部写入文件流中while((len=is.read(buf))!=-1){fos.write(buf, 0, len);}//建立输出流,上传成功后反馈信息OutputStream os = s.getOutputStream();os.write("上传成功".getBytes());//关流fos.close();s.close();} catch (Exception e) {e.printStackTrace();}}}
|--客户端
public class DemoPicClient {public static void main(String[] args)throws Exception {//套接字绑定固定服务器、端口Socket s = new Socket("127.0.0.1",10007);String st =null;File f= null;//建立键盘流,用于接收控制台输入的文件名路径BufferedReader br =new BufferedReader(new InputStreamReader(System.in));//一直输入,直接输入正确文件路径为止while(true ){System.out.println("请输入文件路径:");//G:\test\1.jpgst = br.readLine();f = new File(st);//验证文件是否存在,存在跳出循环if(f.exists()&& f.isFile())break;}//建立文件读取流FileInputStream fis = new FileInputStream(f);//建立文件输出流OutputStream os =s.getOutputStream();//疑问数组byte[] buf = new byte[1024];int len;//全部写出while((len=fis.read(buf))!=-1){os.write(buf, 0, len);}s.shutdownOutput();InputStream is = s.getInputStream();int leng = is.read(buf);String str = new String(buf,0,leng);System.out.println(str);//关流s.close();fis.close();}}
|--并发登录
|--服务端
public class LoginServer {public static void main(String[] args)throws Exception {@SuppressWarnings("resource")//建立10008端口的套接字ServerSocket ss = new ServerSocket(10008);//有客户端连接的话,就开启新的线程while(true){//等待接收客户端的连接Socket s = ss.accept();//开启线程new Thread(new LoginThread(s)).start();;}}}//服务器,实现Runnable接口class LoginThread implements Runnable{private Socket s;LoginThread(Socket s){this.s= s;}//public void run() {try {//文件保存的数据String line =null;//用户是否存在的标志boolean flag =false;//建立接收客户端数据的字符串String name = null;//建立输出流PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//建立输入BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//只对客户端验证3次for(int x=0 ;x<3;x++){//文件关联流一定要放在循环里,放在外面二次循环时,一直在读文件结尾BufferedReader bfr = new BufferedReader(new FileReader("user.txt"));name = br.readLine();if(name == null)break;//没一次对数据文件中的用户逐个验证while((line = bfr.readLine())!=null){if(line.equals(name)){//找到用户后跳出循环flag = true;break;}}//用户存在与否的信息反馈if(flag){System.out.println(name+"已经登录");pw.println(name+",欢迎光临,您已成功登录。");}else{System.out.println(name+"尝试登录…………");pw.println(name+",用户不存在。");}bfr.close();//关流}s.close();//关流} catch (Exception e) {e.printStackTrace();}}}
|--客户端
public class LoginClient {public static void main(String[] args)throws Exception {//建立套接字,绑定的服务器和端口Socket s = new Socket("127.0.0.1",10008);//name用于记录键盘输入的用户String name= null;//键盘输入数据BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//接收服务器端的信息的流BufferedReader br1= new BufferedReader(new InputStreamReader(s.getInputStream()));//向客户端发送信息的流PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//向服务器发送三次数据验证for(int x=0;x<3;x++){name = br.readLine();if(name==null)break;pw.println(name);String info = br1.readLine();System.out.println("info:\t"+info);if(info.contains("欢迎"))break;}//程序结束打印System.out.println("客户端程序结束……");//关流br.close();s.close();}}
|--IE浏览器—服务端
|--服务端
public class ServerDemo {public static void main(String[] args)throws Exception {@SuppressWarnings("resource")//不关ServerSocket资源的声明ServerSocket ss = new ServerSocket(11000);//192.168.1.103while(true){//等待连接Socket s = ss.accept();//输出流PrintWriter pw = new PrintWriter(s.getOutputStream(),true);pw.println("程序员啊啊啊………………");//关套接字s.close();}}}

0 0