---------------------- android培训、java培训、期待与您交流! ----------------------
一、网络编程概述
(一)网络模型
OSI参考模型、TCP/IP参考模型。
(二)网络通讯要素
IP地址:网络中设备的标示。本地回环地址:127.0.0.1
端口号:用于标示进程的逻辑地址,就是不同进程的标示。有效端口:0-65535,其中 0-1024是系统使用或者保留端口。
传输协议:通讯的规则,TCP UDP ....
二、IP地址
IP地址对应的是InetAddress对象
import java.net.*;
class IPDemo
{
public static void main(String[] args)throws Exception
{
//通过InetAddress的静态方法getLocalHost来获取本地主机的IP对象
InetAddress IP = InetAddress.getLocalHost();
System.out.println(IP.toString());
//分别获取主机的主机名和主机地址
System.out.println("name"+IP.getHostName());//获取该IP所对应的主机名
System.out.println("address"+IP.getHostAddress());//获取该IP对象所对 应的IP
//通过主机名获取任意一台主机所对应的IP地址对象
InetAddress ip = InetAddress.getByName("www.baidu.com");
System.out.println(ip.getHostAddress());
System.out.println(ip.getHostName());
}
}
三、TCP和UDP
(一)UDP
将数据源和目的封装在数据包中,不需要建立连接。每个数据包的大小限制在64K内。因为无连接,是不可靠协议。不需要建立连接,速度快。
(二)TCP
需要建立连接,形成传输数据的通道。在连接中进行大数据量传输。通过三次握手完成连接,是可靠协议。因为需要建立连接,效率会稍低。
四、Socket
Socket就是为网络服务提供的一种机制。通信的两端都有Socket。网络通信其实就是Socket间的通信。数据在两个Socket间通过IO传输。
(一)UDP传输
1、DatagramSocket:
此类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服 务的发送或接收点。
DatagramePacket:
此类表示数据报包。数据报包用来实现无连接包投递服务,每条报文 根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一 台机器的多个包可能选择不同的路由,也可能按不同的顺序到达,不对包投递做出保证。
2、建立传输的步骤:
建立发送端,接收端。
建立数据包。
调用Socket的发送接收方法
关闭Socket
注意:发送端和接收端是两个独立的运行程序。
定义发送端:
import java.net.*;
class UDPSendDemo
{
public static void main(String[] args)throws Exception
{
UDPSend.udpSend();
}
}
/*
1.建立UDPSocket服务
2.提供数据,并将数据封装到数据报包中。
3.通过Socket服务的发送功能,将数据包发出去。
4.关闭资源
*/
class UDPSend
{
public static void udpSend()throws Exception
{
//1,创建UDP的Socket服务,通过DatagramSocket对象
DatagramSocket ds = new DatagramSocket(8888);//绑定发送端的端口
//2.确定数据,并封装成数据报包
String s="my first udp!";
byte[] data = s.getBytes();
DatagramPacket dp =
new DatagramPacket(data,data.length,InetAddress.getByName("192.168.0.3"),10000);
//通过Socket服务,将已有的数据报包发送出去,通过send方法。
ds.send(dp);
//关闭资源
ds.close();
}
}
定义接收端:
import java.net.*;
class UDPReceiveDemo
{
public static void main(String[] args) throws Exception
{
UDPReceive.udpReceive();
}
}
/*
定义UDP接收端
1.定义UDPSocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义一个数字标示方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储就收到的字节数据。因为数据包对象中有更多的功能可提取
字节数组中的不同数据信息。
3.通过Socket服务的receive方法将接收到的数据存入已定义好的数据包中
4,通过数据包对象的特有功能,将这些不同的数据取出。
5.关闭资源
*/
class UDPReceive
{
public static void udpReceive()throws Exception
{
//1.创建UDPSocket服务,建立端点并设置相应的端口号
DatagramSocket ds = new DatagramSocket(10000);
//2.定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp= new DatagramPacket(buf,buf.length);
//3.通过receive方法接收数据包,并存入到定义好的数据包中
ds.receive(dp);
//4.通过数据包的方法获取包中不同意义的数据
//获取接收到的数据包中的IP地址 打印控制台
String ip = dp.getAddress().getHostAddress();
//获取包中的数据
String data = new String(dp.getData(),0,dp.getLength());
//获取端口号
int port = dp.getPort();
System.out.println(data+"::"+ip+"::"+port);
//5,关闭资源
ds.close();
}
}
(二)UDP键盘录入方式
事例一 :
import java.net.*;
import java.io.*;
class UDPSendDemo1
{
public static void main(String[] args)throws Exception
{
UDPSend.udpSend();
}
}
/*
1.建立UDPSocket服务
2.提供数据,并将数据封装到数据报包中。
3.通过Socket服务的发送功能,将数据包发出去。
4.关闭资源
*/
class UDPSend
{
public static void udpSend()throws Exception
{
//1,创建UDP的Socket服务,通过DatagramSocket对象
DatagramSocket ds = new DatagramSocket(8888);//绑定发送端的端口
//2.确定数据,数据是从键盘录入的,并封装成数据报包
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//从键盘上读取数据
String line = null;
while((line=bufr.readLine())!=null)
{
if("886".equals(line))
break;
byte[] data= line.getBytes();
DatagramPacket dp =
new DatagramPacket(data,data.length,InetAddress.getByName("192.168.0.3"),10000);
//通过Socket服务,将已有的数据报包发送出去,通过send方法。
ds.send(dp);
}
//关闭资源
ds.close();
}
}
事例二:聊天工具
/*
做一个类似聊天工具的程序
经分析该程序有一个接收端,一个发送端。两端都要独立运行,所以要设置两个线程控制运行
思路:
1、写一个线程类作为接收端
2、再写一个程类序作为发送端
3、让这两个线程同时运行
*/
import java.io.*;
import java.net.*;
class Send implements Runnable
{
private DatagramSocket ds;
Send(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
//读取键盘录入,并封装成数据包
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
byte[] data =line.getBytes();
//封装数据包
DatagramPacket dp=
new DatagramPacket(data,data.length,InetAddress.getByName("192.168.0.3"),10000);
//发送数据包
ds.send(dp);
}
ds.close();
}
catch (Exception e)
{
throw new RuntimeException("数据发送失败");
}
}
}
class Receive implements Runnable
{
private DatagramSocket ds;
Receive(DatagramSocket ds)
{
this.ds= ds;
}
public void run()
{
try
{
while(true)
{
byte[] buf= new byte[1024];
//创建数据包,用于存储收到的数据
DatagramPacket dp =new DatagramPacket(buf,0,buf.length);
//接收
ds.receive(dp);
String ip= dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(data+"::"+ip+"::"+port);
}
}
catch (Exception e)
{
throw new RuntimeException("接收数据失败");
}
}
}
class ChatDemo
{
public static void main(String[] args) throws Exception
{
DatagramSocket send= new DatagramSocket(10002);
DatagramSocket receive = new DatagramSocket(10000);
new Thread(new Send(send)).start();
new Thread(new Receive(receive)).start();
}
}
(二)TCP传输
1、Socket:此类实现客户端套接字。套接字是两台机器间通信的端点。
ServerSocket
2、实现TCP传输的步骤:
建立客户端和服务端;
建立连接后,通过Socket中的IO流进行数据传输;
关闭Socket。
注意:客户端和服务端是两个独立的应用程序。
客户端:
/*
TCP传输
1.TCP分客户端和服务端。
2.客户端对应的对象是Socket。
服务端对应的对象是ServerSocket。
建立TCP客户端
1、创建Socket服务,并指定要连接的主机和端口。
*/
import java.io.*;
import java.net.*;
class ClientDemo
{
public static void main(String[] args) throws Exception
{
//1.建立客户端的Socket服务,指定服务器和服务器端口
Socket s = new Socket("192.168.0.3",10000);
//为了发送数据,应该获取Socket流中的输出流
OutputStream out = s.getOutputStream();
//获取输出流之后,就可以写说了
out.write("my first tcp".getBytes());
//关闭客户端资源
//s.close();
}
}
import java.net.*;
import java.io.*;
/*
TCP 服务端建立
1.建立服务端的Socket服务,用ServerSocket();
并监听一个端口。
2.获取连接过来的客户端对象。通过ServerSocket的accept方法,
没有连接就会等待,所以这个方法是阻塞式的。
3.客户端如果发过来数据,那么服务端要使用客户端的对象,
并获取该客户端对象的读取流来读取发过来的数据。
4.关闭客户端
关闭服务端(可选)
*/
class ServerDemo
{
public static void main(String[] args) throws Exception
{
//建立服务端的Socket服务,并监听一个端口
ServerSocket ss = new ServerSocket(10000);
//获取客户端对象
Socket s=ss.accept();
//通过客户端对象来获取客户端的IP地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
//获取客户端的读取流,去读客户端发来的数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len= 0;
len=in.read(buf);
System.out.println(new String(buf,0,len));
//关闭客户端
//s.close();
//关闭服务端
//ss.close();
}
}
事例二:
/*
客户端和服务端发生互动
*/
import java.io.*;
import java.net.*;
class TCPClient
{
public static void main(String[] args)throws Exception
{
//客户端建立Socket服务
Socket s=new Socket("192.168.0.3",10000);
OutputStream out= s.getOutputStream();
byte[] data="服务端,你好".getBytes();
out.write(data);
//接收服务发来的数据
InputStream in =s.getInputStream();
byte[] buf = new byte[1024];
int len= 0;
len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
class TCPServer
{
public static void main(String[] args) throws Exception
{
//定义服务端的Socket服务
ServerSocket ss= new ServerSocket(10000);
//获取客户端d对象
Socket s= ss.accept();
//获取客户端的ip地址
String ip= s.getInetAddress().getHostAddress();
//读客户端发来的数据
System.out.println(ip);
InputStream in =s.getInputStream();
byte[] buf = new byte[1024];
int len=0;
len=in.read(buf);
System.out.println(new String(buf,0,len));
//想客户端发数据
OutputStream out =s.getOutputStream();
out.write("客户端。你也好".getBytes());
s.close();
ss.close();
}
}
实例三:上传图片
import java.io.*;
import java.net.*;
/*
上传图片客户端
1.建立客户端服务
2.读取要发送的图片
3。用Socket服务将图片上传给服务端
4.读取服务端发来的反馈信息
5.关闭资源
*/
class PicClient
{
public static void main(String[] args) throws Exception
{
//建立客户端服务,并指定服务端
Socket s = new Socket("192.168.0.3",10000);
//读取要上传的图片,用字节输入流
FileInputStream fis = new FileInputStream("C:\\1.jpg");
//获取客户端的输出流,准备上传
OutputStream out = s.getOutputStream();
//开始循环上传
byte[] buf = new byte[1024*4];
int len = 0;
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//发送结束标记
s.shutdownOutput();
//读取服务器反馈来的信息
InputStream in = s.getInputStream();
byte[] buf1 = new byte[1024];
len = 0;
len = in.read(buf1);
System.out.println(new String(buf1,0,len));
fis.close();
s.close();
}
}
/*
上传图片服务端
1.建立服务端
2.获取客户端对象
3.读取客户端上传的图片写到本地文件
4.向客户端反馈信息
5.关闭资源
*/
class PicServer
{
public static void main(String[] args) throws Exception
{
//建立服务端服务,监听相应的端口
ServerSocket ss = new ServerSocket(10000);
//获取客户端对象
Socket s = ss.accept();
//获取客户端ip
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
//获取客户端的输入流,
InputStream in = s.getInputStream();
//创建文件输出流,将读取到的文件存到本地
FileOutputStream out = new FileOutputStream("2.jpg");
byte[] buf = new byte[1024*4];
int len = 0;
while((len=in.read(buf))!=-1)
{
out.write(buf,0,len);
}
//向客户端反馈信息
OutputStream outin = s.getOutputStream();
outin.write("上传成功".getBytes());
out.close();
s.close();
ss.close();
}
}
事例四:服务端并发为客户端服务
import java.io.*;
import java.net.*;
/*
上传图片客户端
1.建立客户端服务
2.读取要发送的图片
3。用Socket服务将图片上传给服务端
4.读取服务端发来的反馈信息
5.关闭资源
*/
class PicClient
{
public static void main(String[] args) throws Exception
{
if (args.length!=1)
{
System.out.println("请确定要上传的图片");
return;
}
File file = new File(args[0]);
if (!(file.exists()&&file.isFile()))
{
System.out.println("文件不存在或错误");
return;
}
if (!(file.getName().endsWith(".jpg")))
{
System.out.println("图片格式错误");
return;
}
if (file.length()>1024*1024*4)
{
System.out.println("文件过大");
return;
}
//建立客户端服务,并指定服务端
Socket s = new Socket("192.168.0.3",10000);
//读取要上传的图片,用字节输入流
FileInputStream fis = new FileInputStream(file);
//获取客户端的输出流,准备上传
OutputStream out = s.getOutputStream();
//开始循环上传
byte[] buf = new byte[1024*4];
int len = 0;
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
}
//发送结束标记
s.shutdownOutput();
//读取服务器反馈来的信息
InputStream in = s.getInputStream();
byte[] buf1 = new byte[1024];
len = 0;
len = in.read(buf1);
System.out.println(new String(buf1,0,len));
fis.close();
s.close();
}
}
/*
这个服务端有一个局限性。一次只能让一个客户使用,要想多个客户端同时并发访问客户端,
就要使用到多线程。
上传图片服务端
1.建立服务端
2.获取客户端对象
3.读取客户端上传的图片写到本地文件
4.向客户端反馈信息
5.关闭资源
*/
class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s )
{
this.s=s;
}
public void run()
{
int count = 1;
//获取客户端ip
String ip = s.getInetAddress().getHostAddress();
try
{
System.out.println(ip);
File file =new File(ip+"("+(count++)+").jpg");
while(file.exists())
{
file=new File(ip+"("+(count++)+").jpg");
}
//获取客户端的输入流,
InputStream in = s.getInputStream();
//创建文件输出流,将读取到的文件存到本地
FileOutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024*4];
int len = 0;
while((len=in.read(buf))!=-1)
{
out.write(buf,0,len);
}
//向客户端反馈信息
OutputStream outin = s.getOutputStream();
outin.write("上传成功".getBytes());
out.close();
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"上传失败");
}
}
}
class PicServer
{
public static void main(String[] args) throws Exception
{
//建立服务端服务,监听相应的端口
ServerSocket ss = new ServerSocket(10000);
while (true)//循环获取客户端对象
{
//获取客户端对象
Socket s = ss.accept();
new Thread(new PicThread(s)).start();//开启一个客户端线程
}
}
}
事例五:客户端并发登陆
/*
客户端并发登陆
客户通过键盘录入用户名,服务端对这个用户名进行校验。
如果用户名存在,在服务端显示xxxy已登录,并在客户端显示xxx,欢迎光临
如果该用户不存在,在服务端显示,xxx,尝试登陆。并在客户端显示xxx,该用户不存在。
最多登陆三次
*/
import java.io.*;
import java.net.*;
class LoginClient
{
public static void main(String[] args) throws Exception
{
//定义客户端
Socket s= new Socket("192.168.0.3",10000);
//获取键盘读取流
BufferedReader bufr=
new BufferedReader(new InputStreamReader(System.in));
//获取Socket输出流
PrintWriter out= new PrintWriter(s.getOutputStream(),true);
//获取Socket输入流
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
//判断用户登陆的次数 最多3次
for (int x=0;x<3;x++ )
{
//读取键盘录入,
String line = bufr.readLine();
//如果客户端发的数据为空,则退出
if (line==null)
{
break;
}
//发给服务端
out.println(line);
//获取服务端反馈的信息
String info = bufIn.readLine();
System.out.println(info);
//如果登陆成功,则不再循环判断
if (info.contains("欢迎光临"))
break;
}
bufr.close();
s.close();
}
}
//定义客户端并发执行的线程
class UserThread implements Runnable
{
private Socket s;
UserThread(Socket s)
{
this.s=s;
}
public void run()
{
//获取客户端的ip
String ip =s.getInetAddress().getHostAddress();
System.out.println(ip);
try
{
//服务端循环判断登陆次数 最多3次
for (int x=0;x<3 ;x++ )
{
//定义文件读取流
BufferedReader bufr =
new BufferedReader(new FileReader("user.txt"));
//获取Socket读取流
BufferedReader bufIn =
new BufferedReader(new InputStreamReader(s.getInputStream()));
//获取Socket输出流
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//读取用户输入的数据
String line = bufIn.readLine();
if (line==null)
{
break;
}
String name = null;
boolean flag = false;
//循环读取文件中的数据和用户输入的数据比较
while ((name=bufr.readLine())!=null)
{
if (name.equals(line))
{
flag =true ;
break;
}
}
if(flag)
{
out.println(name+",欢迎光临");
System.out.println(name+",已登录");
break;
}
else
{
System.out.println(line+",尝试登陆");
out.println(line+",不存在");
}
}
s.close();//注意:读取流不能关
}
catch (Exception e)
{
throw new RuntimeException("校验失败");
}
}
}
class LoginServer
{
public static void main(String[] args) throws Exception
{
//建立服务端服务
ServerSocket ss = new ServerSocket(10000);
//循环判断是否有服务连接
while(true)
{
//获取客户端对象
Socket s =ss.accept();
//开启为客户端服务的线程
new Thread(new UserThread(s)).start();
}
}
}
四、URL-URLConnection
(一)URL :此类代表统一资源定位符,它是指向互联网“资源”的指针。
1、常用方法:
String getFile();获取此URL的文件名
String getHost();获取url的主机名
String getPath();获取此URL的路劲部分
int getPort();获取此url的端口号
String getProtocol();获取url的协议名称
String getQuery();获取url的查询部
2、URLConnection是一个抽象类,里边封装了Socket服务。作用于应用层。
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class MyIE
{
public static void main(String[] args) throws Exception
{
new MyWindow();
}
}
class MyWindow
{
//首先定义组件引用
private Frame f;
private TextField tf;
private Button b;
private TextArea ta;
private Dialog d;
private Label lab;
private Button labb;
MyWindow()throws Exception
{
init();
}
//定义窗体初始化函数
public void init()throws Exception
{
//创建窗体对象
f=new Frame("my window");
//设置窗体
f.setBounds(300,200,600,500);
f.setVisible(true);
//设置窗体布局
f.setLayout(new FlowLayout());
//创建组件并把组件添加到窗体中
tf=new TextField(50);
b=new Button("转到");
ta=new TextArea(25,70);
d=new Dialog(f,"我的提示信息",true);
//f:表示该对话框属于f窗体,true:代表对话框的模式,
//true表明你不处理,他所属的窗体你就操作不了!
lab=new Label();
labb=new Button("确定");
d.add(lab);
d.add(labb);
d.setLayout(new FlowLayout());
d.setBounds(400,300,250,100);
f.add(tf);
f.add(b);
f.add(ta);
MyEvent();
}
//定义窗体事件函数
private void MyEvent()throws Exception
{
labb.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
//添加按钮活动监听器
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
showDir();
}
catch (Exception ex)
{
}
}
});
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
try
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showDir();
}
catch (Exception ex)
{
}
}
});
}
private void showDir()throws Exception
{
//ta.setText("");
String dirPath = tf.getText();
URL url = new URL(dirPath);
URLConnection conn=url.openConnection();
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len=0;
while((len=in.read(buf))!=-1)
{
ta.append(new String(buf,0,len));
}
}
}
五、域名解析
将主机名翻译成IP地址,需要域名解析服务器:DNS。一个域名对应一个IP地址。在解析时用的是“就近原则”。
---------------------- android培训、java培训、期待与您交流! ----------------------