首先先介绍一下InetAddress和URL类
URL类:
类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。其实,它就是为我们提供切割URL字符串,为我们获取相应的URL信息。
通过下面一段代码简单的说明其常用的功能:
import java.io.InputStream; import java.net.URL; import java.net.URLConnection; public class URLDemo { public static void main(String[] args)throws Exception{ // TODO Auto-generated method stub //目标是我自己写的一个server URL url=new URL("Http://127.0.0.1:10000"); //获取此 URL 的文件名。 System.out.println("File:"+url.getFile()); //获取此 URL 的主机名(如果适用)。 System.out.println("getHost:"+url.getHost()); //获取此 URL 的路径部分。 System.out.println("getPath:"+url.getPath()); //获取此 URL 的端口号。 如果为默认端口,则返回-1,需要自己指定 System.out.println("getPort:"+url.getPort()); //获取此 URL 的协议名称。 System.out.println("getProtocol:"+url.getProtocol()); //获取此 URL 的查询部分。 System.out.println("getQuery:"+url.getQuery()); //建立连接,功能相当于socket,但是不同的是同工作在应用层,不用关闭链接 URLConnection connection=url.openConnection(); InputStream is=connection.getInputStream(); int len=0; byte[]bt=new byte[1024]; while((len=is.read(bt))!=-1){ System.out.println(new String(bt,0,len)); } } }
运行结果如下:
File:/name.html?name=chu getHost:127.0.0.1 getPath:/name.html getPort:10000 getProtocol:http getQuery:name=chu
上述程序有两个特殊的方法:
openConnection(),此方法返回的是一个URLConnection类,表示和目标服务器建立连接,相当于完成Socket的三次握手,即连接工作;但是和Socket不同的是,Socket工作在传输层,而它工作在用于层;它把Socket封装在自己类中;组装出自己的功能
另一个就是openStream()方法,此方法返回的是一个InputStream流对象,查看JDK文档,可以知道它就是URLConnection connection=url.openConnection();
InputStream is=connection.getInputStream();两者的组合;即url.openConnection().getInputStream();
InetAddress类
此类表示互联网协议 (IP) 地址。 简单的说它就代表IP地址对象,用来操作IP地址的,此类没有构造函数,只有通过自身的静态方法获取该类的对象;
一般而言,其方法为getbyXXX()基本就是返回其自身对象的。比如说:getAllByName();此方法返回的是一个InetAddress的数组;因为同一个域名可能有多个IP地址;其它,就是getByAddress(),getByName();但有一个特殊的方法也是返回InetAddress,即getLocalHost();返回本地主机。
接下来看段代码:
import java.net.InetAddress; public class URLDemo { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub //因为InetAddress没有构造函数,只能通过调用自身静态方法产生 InetAddress ip=InetAddress.getByName("127.0.0.1"); //获取主机地址 System.out.println("address="+ip.getHostAddress()); //获取主机名,由于Host文件中配置了 127.0.0.1 activate.adobe.com System.out.println("name="+ip.getHostName()); } }
运行结果如下:
address=127.0.0.1 //Host文件中配置了 127.0.0.1 activate.adobe.com name=activate.adobe.com
因为我在Host文件中配置了 127.0.0.1 activate.adobe.com,所以,name为activate.adobe.com
还有一个常用的用法
String ip=dp.getAddress().getHostAddress();即InetAddress.getHostAddress()方法获取Ip字符串。
注:dp.getAddress()返回的是一个InetAddress类。
下面举一个实例:通过UDP传输方式,将一段文字数据发送出去。
发送端设计思路如下:
1、建立UDPSocket服务;
2、提供数据,并将数据封装到数据包中,注意:最终发送的都是字节流;
3、通过Socket服务的发送功能,将数据包发送出去;
4、关闭资源。
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPSend { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub //创建udp服务,通过DatagramSocket()对象 DatagramSocket ds=new DatagramSocket(); //确定存储数据的字节数组 byte[]buf=new byte[1024]; buf="正在学习黑马视频教程!".getBytes(); //将数据封装为数据包,并指定目标Ip以及端口号 DatagramPacket dp=new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"),10000); //发送数据 ds.send(dp); //关闭资源 ds.close(); } }
接受端设计思路如下:
1、定义udpsocket服务,并指定监听端口;
2、定义一个数据包,因为要存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中 的不同数据信息;
3、通过socket服务的receive方法接收到的数据存入已经定义好的数据包中;
4、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上;
5、关闭资源。
用于接收udp协议传输的数据并进行处理
import java.net.DatagramPacket; import java.net.DatagramSocket; public class UDPReceive { public static void main(String[] args)throws Exception { // TODO Auto-generated method stub //创建udp socket,建立端点 //指定监听端口号 DatagramSocket ds=new DatagramSocket(10000); //定义数据包,存储接收到的数据 byte[]buf=new byte[1024]; //此构造方法用来接收数据,一共有两种构造方法用来接收,另一种DatagramPacket(byte[]by,ing offset,int length) DatagramPacket dp=new DatagramPacket(buf,buf.length); //通过receive方法接收到的数据存入数据包中,Receive方法为阻塞式方法 ds.receive(dp); //获取数据 String data=new String(dp.getData(),0,dp.getLength()); String data1=new String(buf,0,buf.length); //获取源ip String ip=dp.getAddress().getHostAddress(); //获取源端口号 int port=dp.getPort(); System.out.println("data:"+data); System.out.println("ip:"+ip); System.out.println("port:"+port); System.out.println("data1:"+data1); //关闭资源 ds.close(); } }
测试要先运行接收程序,再运行发送程序.如果接收程序没有接收到数据,则会一直阻塞,接收到数据后才会关闭程序。如果网络上没有数据发送过来,接收程序也没有阻塞,通常都是使用了一个已经被占用的端口。
运行结果如下:
data:正在学习黑马视频教程! ip:127.0.0.1 port:61045 data1:正在学习黑马视频教程!
有关TCP的应用
应用举例:建立一个文本转换服务器
客户端给服务端发送文本,服务端将文本转换成大写在返回给客户端,而且客户端可以不断的进行文本转换,当客户端输入over时,转换结束。
分析
客户端:
既然是操作设备上的数据,那么就可以用Io技术,并且按照IO操作规律来思考
源:键盘录入
目的:网络设备,网络输出流,而且操作的是文本数据,可以选择字符流
步骤
1.建立服务
2.获取键盘录入
3.将数据发给服务器
4.返回服务端的大写数据
服务端代码如下:
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 TCPServer { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub try{ ServerSocket st=new ServerSocket(10000); Socket s=st.accept(); String ip=s.getInetAddress().getHostAddress(); System.out.println("ip..."+ip+"....connection........"); //读取socket读取流中的数据 BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));//第一种写法 //目的,socket输出流,将大写数据写入到socket输出流,并发送到客户端 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); //PrintWriter bs=new PrintWriter(s.getOutputStream(),true);第二种写法 String line=null; while((line=br.readLine())!=null){ System.out.println(line); bw.write(line.toUpperCase()); bw.newLine(); bw.flush(); //bs.println(line.toUpperCase());第二种写法 } }catch(Exception e){ e.printStackTrace(); } } }
在这个程序里,创建了一个在10000端口上等待连接的ServerSocket对象,当接收到一个客户的连接请求后,程序从与这个客户建立了连接的Socket对象中获得输入输出流对象,通过输出流首先向客户端发送一串字符,然后通过输入流读取客户端发送过来的信息,并将这些信息打印,然后关闭所有资源。
要先运行服务器程序,然后才能运行客户端程序,当TCP服务器程序运行到Socket.accpet()方法等待客户连接时,accept方法将阻塞,一直到有客户连接请求到来,该方法才会返回,如果又没有请求到来,又没有发生阻塞,通常都是使用了一个已经被占用的端口.。
客户端代码如下:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class TCPClient { public static void main(String[] args)throws Exception { // TODO Auto-generated method stub try{ Socket s=new Socket("127.0.0.1",1000); //定义读取键盘数据流对象 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); //定义目的,将数据写入socket输出流,发给服务器端 //BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); //第一种写法 BufferedReader buf=new BufferedReader(new InputStreamReader(s.getInputStream())); //定义一个socket读取流,读取服务端返回的大写信息 //第二种写法 PrintWriter pw=new PrintWriter(s.getOutputStream(),true); String line=null; while((line=br.readLine())!=null){ if("over".equals(line))break; //bw.write(line);第一种写法 //bw.newLine();因为readline()的结束标记是以换行为标记的,所以必须得加 //bw.flush(); String str=buf.readLine(); System.out.println("data="+str); //第二种写法 pw.println(line); } br.close(); s.close(); }catch(Exception e){ e.printStackTrace(); } } }
下面举一个多线程上传图片的应用例子
服务端程序:
import java.io.*; import java.net.*; public class FilesServerDemo { public static void main(String[] args) { // TODO Auto-generated method stub try{ ServerSocket ss=new ServerSocket(10000); while(true){ Socket s=ss.accept(); new Thread(new PicThread(s)).start(); } }catch(Exception e){ throw new RuntimeException("上传失败"); } } }
import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class UploadPicture implements Runnable { private Socket s; UploadPicture(Socket s){ this.s=s; } @Override public void run(){ // TODO Auto-generated method stub int count=1; String ip=s.getInetAddress().getHostAddress(); System.out.println(ip+"......connection"); try{ File file=new File(ip+"("+count+")"+".jpg"); while(file.exists()) file=new File(ip+"("+(count++)+")"+".jpg"); FileOutputStream fos=new FileOutputStream(file); InputStream is=s.getInputStream(); OutputStream out=s.getOutputStream(); int len=0; byte[]bt=new byte[1024]; while((len=is.read(bt))!=-1){ fos.write(bt,0,len); } out.write("图片上传成功".getBytes()); s.close(); fos.close(); } catch(Exception e){ throw new RuntimeException("图片上传失败!"); } } }
客户端程序:
import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class PictureClient { public static void main(String[] args) { // TODO Auto-generated method stub if(args.length!=1){ System.out.println(" please choose a pic"); return; } if(!args[0].endsWith(".jpg")){ System.out.println("请上传一个jpg格式的图片!"); return; } File f=new File(args[0]); if(!(f.exists()&&f.isFile())){ System.out.println("请上传一个存在的文件!"); return; } if(f.length()>1024*1024*5){ System.out.println("请上传一个文件大小不超过6M的文件!"); return; } try{ Socket s=new Socket("127.0.0.1",10000); FileInputStream fs=new FileInputStream(f); OutputStream out=s.getOutputStream(); InputStream in=s.getInputStream(); byte[]bt=new byte[1024]; int len=0; while((len=fs.read(bt))!=-1){ out.write(bt,0,len); } s.shutdownOutput(); int l=0; byte[]bb=new byte[1024]; while((l=in.read(bb))!=-1){ System.out.println(new String(bb,0,l)); } s.close(); fs.close(); }catch(Exception e){ throw new RuntimeException("图片上传文件失败"); } } }
模仿Tomcat服务器的一个应用举例
import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TomcatDemo { public static void main(String[] args)throws Exception { // TODO Auto-generated method stub ServerSocket st=new ServerSocket(10004); //获取客户端的Socket Socket sk=st.accept(); //获取输入流对象 InputStream is=sk.getInputStream(); byte[]bs=new byte[1024]; //读取数据 int len=is.read(bs); String data=new String(bs,0,len); String ip=sk.getInetAddress().getHostAddress(); System.out.println("ip......."+ip+'\n'+"data="+data); //BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(sk.getOutputStream(),"gbk")); OutputStream bw=sk.getOutputStream(); bw.write("黑马欢迎您!".getBytes()); System.out.println("黑马欢迎您!"); //关闭客户端Socket流 sk.close(); st.close(); } }
其实,Tomcat服务器就是一个服务端的ServerSocket
采用了多线程
需求分析:
客户端通过键盘录入用户名
服务器对这个用户名进行校验
如果该用户名存在,在服务器端显示xxx已经登录
并在客户端显示xxx,欢迎光临
如果该用户名不存在,在服务器端显示xxx尝试登录
并在客户端显示xxx,该用户名不存在
做多就登录三次
服务端程序:
import java.net.ServerSocket; import java.net.Socket; public class UserLoginServerDemo { public static void main(String[] args)throws Exception { // TODO Auto-generated method stub ServerSocket ss=new ServerSocket(10008); while(true){ Socket s=ss.accept(); new Thread(new UserLoginThread(s)).start(); } } }
客户端端程序:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; public class UserLoginThread implements Runnable { private Socket s; UserLoginThread(Socket s){ this.s=s; } @Override public void run() { // TODO Auto-generated method stub try{ String ip=s.getInetAddress().getHostAddress(); System.out.println(ip+".......connnection"); for(int i=0;i<3;i++){ BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream())); String name=br.readLine(); BufferedReader buf=new BufferedReader(new FileReader("user.txt")); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); String line=null; boolean flag=false; while((line=buf.readLine())!=null){ if(line.equals(name)) { flag=true; break; } } if(flag){ System.out.println(name+"欢迎,登录成功"); bw.write(name+"欢迎,登录成功"); bw.flush(); break; }else{ System.out.println(name+"登录未成功"); bw.write(name+"登录未成功"); bw.newLine(); bw.flush(); } } s.close(); }catch(Exception e){ e.printStackTrace(); } } }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class UserLoginClientDemo { public static void main(String[]args)throws Exception{ Socket s=new Socket("127.0.0.1",10008); BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); PrintWriter pw=new PrintWriter(s.getOutputStream(),true); BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); for(int i=0;i<3;i++){ String line=br.readLine(); if(line==null)break; pw.println(line); String le=bufr.readLine(); System.out.println(le); if(le.contains("欢迎您的登陆!")){ break; } } s.close(); br.close(); } }
模拟简单聊天程序(采用了多线程编程思想)
服务端端程序:
import java.net.DatagramPacket; import java.net.DatagramSocket; public class ReceiveServer implements Runnable { private DatagramSocket ds; ReceiveServer(DatagramSocket ds){ this.ds=ds; } @Override public void run() { // TODO Auto-generated method stub while(true){ try{ byte[]b=new byte[1024*64]; DatagramPacket dp=new DatagramPacket(b,0,b.length); ds.receive(dp); String data=new String(dp.getData(),0,dp.getLength()); String ip=dp.getAddress().getHostAddress(); System.out.println("data:"+data); System.out.println("ip:"+ip); }catch(Exception e){ throw new RuntimeException("运行失败"); } } } }
客户端端程序:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class SendClient implements Runnable{ private DatagramSocket ds; SendClient(DatagramSocket ds){ this.ds=ds; } public void run(){ try{ BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String line=null; while((line=br.readLine())!=null){ if("byby".equals(line))break; byte[]b=line.getBytes(); DatagramPacket dp=new DatagramPacket(b,0,b.length,InetAddress.getByName("127.0.0.1"),10006); ds.send(dp); } ds.close(); }catch(Exception e){ throw new RuntimeException("运行出错!"); } } }
主程序:用于测试
import java.net.DatagramSocket; public class LiaotianMain { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub DatagramSocket ds=new DatagramSocket(); DatagramSocket dt=new DatagramSocket(10006); new Thread(new SendClient(ds)).start(); new Thread(new ReceiveServer(dt)).start(); } }
运行结果:
您好! data:您好! ip:127.0.0.1 欢迎来到黑马学习 data:欢迎来到黑马学习 ip:127.0.0.1 努力中 data:努力中 ip:127.0.0.1
通过以上应用举例,可以总结出使用JAVA网络编程的一般设计步骤如下:
1、建立客户端的Socket对象,客户端连接到服务器;
2、服务器端:
a. 建立ServerSocket对象;
b. 指定端口;
c. 获取客户端Socket,通过accept()方法,注意此方法为阻塞式方法;
d. 服务端关闭端口。其实,现实应用中,很多大型的公司都不会关闭服务端端口;
e. 服务端没有专门的流对象,通过获取客户端的流对象进行操作;
f. 一般用到网络编程,都会用到IO流操作TCP和UDP基本情况就是这样;注意,Socket服务于传输层,建立连接,实际上是建立Socket流,而Socket流包括输入,输出流。
相关推荐
《C#网络应用编程》是一本致力于教授C#语言进行网络编程的书籍,作者Richard Blum是一位拥有丰富网络和系统管理经验的专业人士,他的工作经验为本书提供了深厚的理论与实践经验支撑。书中不仅介绍C#的基础网络编程...
《C#网络编程及应用》课程的课件涵盖了C#语言在网络编程领域的广泛知识,旨在帮助学习者理解和掌握网络通信的基础以及如何利用C#进行实际的网络应用开发。以下是本课程涉及的一些关键知识点: 1. **C#语言基础**:...
本主题主要聚焦于“网络编程 物联网应用 传感器网络编程”,涉及到C51微控制器和CC2430无线通信芯片的使用,以及如何通过编程设计实现灵活的网络拓扑结构。 首先,C51是一种专门针对8051系列微控制器的高级编程语言...
第01章-网络应用编程入门知识;第02章-数字墨迹与动态绘图基础;第03章-进程、线程与应用程序域;第04章-数据流与数据的加密和解密;第05章-异步编程;第06章-并行编程;第07章-WCF入门;第08章-WCF和HTTP应用编程;...
TCP/IP网络协议:传统的网络编程技术,包括套接字编程、TCP应用编程和UDP应用编程。套接字是操作系统为程序员提供的网络服务接口,位于应用层和传输层之间。 套接字编程 套接字编程是使用Socket类来实现网络通信的...
网络编程技术及应用C篇是深入探讨如何使用C语言进行网络通信编程的专题,其中特别关注了winpcap这一强大的网络数据包捕获库。在本文中,我们将深入理解网络编程的基本概念,C语言在网络编程中的应用,以及winpcap库...
《iOS网络编程与云端应用》是一本深入探讨iOS平台网络编程和云端应用开发的专业书籍,由关东升撰写。本书旨在帮助iOS开发者掌握网络通信的基本原理和实践技巧,以及如何利用云端服务提升应用的功能和用户体验。 一...
《C#网络应用编程(第3版)》是由马骏主编,人民邮电出版社出版的一本深入探讨C#网络编程的书籍。这本书旨在帮助开发者掌握使用C#语言进行网络应用程序开发的技术和方法。源代码是学习过程中不可或缺的一部分,它...
《C#网络应用编程(第2版)》是一本深入探讨C#网络编程技术的书籍,旨在为初学者提供坚实的理论基础,同时也为有经验的开发者提供进一步提升的资源。这本书详细介绍了C#语言在网络编程领域的应用,涵盖了从基础知识到...
《网络编程及Internet应用》这一主题涵盖了广泛的IT知识领域,主要关注如何利用计算机网络进行通信以及在Android平台上实现网络功能。下面将详细阐述这个领域的关键知识点。 首先,网络编程是构建分布式系统的基础...
C#网络编程是开发高效、安全的网络应用程序的关键技能,主要涉及到C#语言与网络通信相关的API,如Socket、TcpClient、TcpListener等。本课件聚焦于C#在网络编程中的应用,旨在帮助学习者掌握如何利用C#进行数据传输...
《C#网络应用编程》是马骏先生撰写的一本深入探讨C#在构建网络应用程序方面的专著,第三版更是对前两版的完善和提升,旨在帮助开发者掌握使用C#进行网络编程的核心技术和实践方法。这本书涵盖了从基础的网络概念到...
C#的网络应用编程涵盖了多种类型的应用,包括但不限于控制台应用程序、Windows应用程序、水晶报表应用程序、ASP.NET Web应用程序、Web服务应用程序以及智能设备应用程序。这使得C#能够构建从桌面应用到分布式Web系统...
《马骏 C#网络应用编程实验指导与开发实例》是一本深入探讨C#语言在网络编程领域的实践教程。这本书旨在帮助读者掌握使用C#进行网络应用开发的核心技术和实战技巧。通过详细的实验指导和丰富的开发实例,读者可以...
总的来说,《C#网络应用编程(第2版)》是一本理论与实践相结合的优秀教材,适合有一定C#基础并希望提升网络编程能力的开发者阅读。通过学习,你可以掌握网络编程的核心技术,为构建高效、稳定的网络应用打下坚实的...
.NET框架为C#开发者提供了丰富的网络编程API,使得开发者可以方便地实现基于这些协议的应用。例如,System.Net命名空间下的Socket类,它允许开发者直接操作套接字,实现基于TCP或UDP的通信。同时,HttpWebRequest和...
Windows 网络编程是指在 Windows 操作系统平台上进行网络编程的技术,涉及到 Windows Socket、网络协议、网络应用程序的开发等方面。 Windows 网络编程的主要目的是实现高性能的网络应用程序,以满足大型网络游戏、...
《网络编程技术及应用》是一门深入探讨网络通信编程的课程,主要针对计算机科学和技术、软件工程等相关领域的学习者。在网络编程中,我们通常涉及到如何让计算机通过网络进行数据交换,实现不同设备间的通信。这门...
C#网络应用编程 中文书籍PDF格式
Python网络编程在Linux环境下是一个强大的工具,用于构建服务器端应用程序和服务。这个主题涵盖了多个关键知识点,包括基础概念、Python的网络库、套接字编程、并发处理以及在Linux系统中的应用。 1. **网络编程...