Java网络编程-应用练习篇
这一篇主要是一些常见应用分析和练习。
练习一:
/*
通过tcp协议,客户端上传图片给服务端,服务端将图片数据发送到指定目的(硬盘)
并给客户端返回上传成功。
分析步骤:
客户端
1,创建socket服务指定客户端点
2,读取客户端指定图片数据
3,通过socket输出流将图片数据发送服务端并定义结束标记
4,通过流对象接收服务端返回的上传信息
5,关闭流资源
服务端
1,创建ServerSocket服务端并指定端口号
2,读取客户端发送来的图片数据并存储缓冲区
3,将缓冲区里的数据写入到指定目的地
4,返回客户端上传信息
5,关闭流资源。
*/
import java.net.*;
import java.io.*;
class PicClient{//客户端
public static void main(String[] args) throws Exception{
Socket s = new Socket("192.168.0.2",10006);
//读取指定的图片
FileInputStream fis =
new FileInputStream(new File("c:\\背景.jpg"));
//Socket服务的输出流将数据发送
OutputStream out = s.getOutputStream();
//定义一个缓冲区
byte[] buy = new byte[1024];
int len = 0;
while ((len= fis.read(buy))!=-1){
out.write(buy,0,len);
}
//定义结束标记,告诉服务端数据传送完毕
s.shutdownOutput();
//通过socket读取流,读取服务端返回的信息
InputStream is = s.getInputStream();
byte[] b = new byte[1024];
int leng = is.read(b);
System.out.println(new String(b,0,leng));
fis.close();
s.close();
}
}
class PicServer//服务端{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();
//获取客户端iPhone地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
InputStream is = s.getInputStream();
FileOutputStream fos = new FileOutputStream("c:\\复制图片.jpg");
byte[] buy = new byte[1024];
int len = 0;
while ((len=is.read(buy))!=-1){
fos.write(buy,0,len);
}
OutputStream os = s.getOutputStream();
os.write("上传成功".getBytes());
fos.close();
s.close();
ss.close();
}
}
练习二:
TCP客户端并发上传图片
思考问题:
1, 通过上面的练习了解到,这是一个单线程的服务,其局限性是当a客户连接服务端后正常秩序流程,若b客户想要连接只能等待,因为服务端必须把a客户端的请求处理完才能执行b客户端的请求,所以暂时获取不到b客户端对象。
2, 若客户端发送过来的文件不是图片文件或者文件过大怎办?
解决:
1, 为了让多个客户可以同时并发访问服务端,服务端最好的方法就是把每个客户封装到单独的一个线程中,这样就可以同时处理多个客户的请求。
2, 创建文件对象,判断传送进来的文件是否符合指定规则,若不符合返回信息。
怎么定义线程呢?
只要明确了每个客户端在服务端执行的代码,将代码存入run方法即可
示例:
/*
客户端并发请求的练习
*/
import java.net.*;
import java.io.*;
class PicClientDemo{
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*8){
System.out.println("传入的文件大于8M");
return;
}
Socket s = new Socket("192.168.0.2",10006);
//读取指定的图片
FileInputStream fis =
new FileInputStream(file);
//Socket服务的输出流将数据发送
OutputStream out = s.getOutputStream();
//定义一个缓冲区
byte[] buy = new byte[1024];
int len = 0;
while ((len= fis.read(buy))!=-1){
out.write(buy,0,len);
}
//定义结束标记,告诉服务端数据传送完毕
s.shutdownOutput();
//通过socket读取流,读取服务端返回的信息
InputStream is = s.getInputStream();
byte[] b = new byte[1024];
int leng = is.read(b);
System.out.println(new String(b,0,leng));
fis.close();
s.close();
}
}
//利用多线程实现并发上传数据
class PicThread implements Runnable{
private Socket s;
PicThread(Socket s){
this.s = s;
}
public void run(){
try{
//获取客户端iP地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
InputStream is = s.getInputStream();
int count = 1;
//文件保存路径
File dir = new File("c:\\");
File file = new File(dir,"复制图片.jpg");
//判断文件是否存在
while (file.exists()){
file = new File(dir,"复制图片("+(count++)+").jpg");
}
//将上传的数据存进指定输出流
FileOutputStream fos = new FileOutputStream(file);
byte[] buy = new byte[1024];
int len = 0;
while ((len=is.read(buy))!=-1){
fos.write(buy,0,len);
}
//返回上传信息给客户端
OutputStream os = s.getOutputStream();
os.write("上传成功".getBytes());
fos.close();
s.close();
}
catch (Exception e){
throw new RuntimeException("数据上传失败");
}
}
}
class PicServerDemo{
public static void main(String[] args) throws Exception{
//创建服务端Socket服务,监听端口
ServerSocket ss = new ServerSocket(10006);
//主线程循环执行或将上传的客户端数据
while (true){
//获取客户端对象
Socket s = ss.accept();
//创建并开启客户端线程
new Thread(new PicThread(s)).start();
}
}
}
练习三:
/*
练习:客户端并发登陆
客户端通过键盘录入用户名,服务端对这个用户进行校验。
若该用户存在,在服务端显示XXX,已登录;并在客户端显示XXX,欢迎光临。
若用户不存在,在服务端显示XXX,尝试登陆;
并在客户端显示XXX,该用户不存在,且最多登陆三次
*/
import java.net.*;
import java.io.*;
//客户端
class LoginClinet{
public static void main(String[] args) throws Exception{
//创建服务
Socket s = new Socket("192.168.0.2",10007);
//键盘录入
BufferedReader bufs =
new BufferedReader(new InputStreamReader(System.in));
//使用Socket的输出流将数据写入
PrintWriter ps = new PrintWriter(s.getOutputStream(),true);
//接收服务器返回的信息
BufferedReader br =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
//设置登陆次数
for (int x = 1;x<=3 ;x++ ){
line = bufs.readLine();//获取键盘信息
if(line==null)
break;
ps.println(line);//将数据发送服务端
String info = br.readLine();//获取服务端返回信息
System.out.println(info);
if (info.contains("欢迎"))
break;
}
bufs.close();
s.close();
}
}
//利用多线程实现并发登陆
class LoginThread implements Runnable{
private Socket s;
LoginThread(Socket s){
this.s = s;
}
public void run(){
try{
for (int x = 1;x<=3 ;x++ )//在服务端限制登陆次数{
//获取客户端ip地址
String ip = s.getInetAddress().getHostAddress();
System.out.println("客户端iP:"+ip);
//通过socket服务读取流获取客户端发送的信息
BufferedReader bufr =
new BufferedReader(new InputStreamReader(s.getInputStream()));
//关联数据库,查询是否有该客户端信息,这时自定义数据库一个文本文件内存储的是用户名
BufferedReader in =
new BufferedReader(new FileReader("c:\\users.txt"));
String line = bufr.readLine();//获取信息
if (line==null){
break;//当接收的是null时退出
}
String data = null;
boolean flag = false;
while ((data= in.readLine())!=null){
if (line.equals(data)){
flag = true;
break;
}
}
//通过socket服务输出流,给发送客户端登陆信息
PrintWriter ps = new PrintWriter(s.getOutputStream(),true);
if (flag){
ps.println(line+",欢迎光临");
System.out.println(line+",已登录");
break;
}
else{
ps.println(line+"该用户不存在,请重新登陆");
System.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(10007);//创建服务端并监听端口;
while (true){
Socket s = ss.accept();//获取客户端对象
new Thread(new LoginThread(s)).start();//创建并开启多线程
}
}
}
模拟数据库:
打印结果:
练习三(关于浏览器客户端显示):
/*
浏览器客户端-自定义服务端
浏览器是一个标准的客户端,它可以对服务端传输过来的数据进行解析,
把符合应用层协议的消息部分解析后,将头信息拆包,传送到应用层,
只保留正确的正文主题部分县市在客户端上。
因为java编译使用的是传输层和网际层处理数据,所以接收全部消息
并包含头消息。浏览器处于应用层,编译时将头消息编译,只留下主题信息
示例:
演示客户端和服务端
客户端:浏览器
服务端:自定义
*/
import java.net.*;
import java.io.*;
class ServerDemo{
public static void main(String[] args)throws Exception {
ServerSocket ss = new ServerSocket(11000);
Socket s = ss.accept();
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("<font color='red' size='7'>浏览器您好,我是服务端发送给您的消息。</font>");
s.close();
ss.close();
}
}在浏览器输入ip地址加端口号即可显示
URL-URLConnection
概述:
类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。
URI:范围大,条形码等也包含咋此范围内
URL:范围小即域名
常用构造方法:
//根据指定 protocol、host、port号和 file 创建 URL对象。
URL(String protocol,String host,int port,String file);
常用方法:
getFile() | |
getHost() | |
getPath() | |
int | getPort() |
getProtocol() | |
getQuery() |
URLConnection
抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源
openConnection();//对影响到远程资源连接的参数进行操作。
示例:
/*
需求:
自定义图形化界面浏览器即客户端
分析步骤:
1,自定义浏览器构造图形化界面
2,注册事件监听机制
3,通过创建URL对象接收服务端发送来的数据
*/
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
class MyIEDemo{
//定义所需组件引用
private Frame f;
private Button but;
private TextArea ta;
private TextField tf;
//构造函数
MyIEDemo(){
info();
}
private void info(){
//组件实例化
f = new Frame("我的网页窗口");
ta = new TextArea(60,50);
tf = new TextField(40);
but = new Button("搜索");
//对窗口进行设置
f.setBounds(300,200,400,370);
f.setLayout(new FlowLayout());
//添加组件
f.add(tf);
f.add(but);
f.add(ta);
//事件监听
myEvent();
//显示窗口
f.setVisible(true);
}
private void myEvent(){
//对窗口注册关闭监听
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
//对按钮注册活动监听
but.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
showFile();//若点击按钮,就会将收索的内容显示文本区
}
});
//对文本框注册键盘监听
tf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if (e.getKeyCode()==KeyEvent.VK_ENTER)
showFile();//若敲回车就会就会将收索的内容显示文本区
}
});
}
private void showFile(){
//清空文本区
ta.setText("");
//获取键盘录入的路径
String path = tf.getText();
try{
/*
重点分析:这里就不用写socket,因为它已经封装进了URL里面,
并且还封装了HTTP等协议,现在就不再传输层而是在应用层。
*/
//将地址封装成对象
URL url = new URL(path);
//链接网页服务器,对远程资源连接的参数进行操作。
URLConnection conn = url.openConnection();
//读取流,用于读取服务器返回数据
InputStream in = conn.getInputStream();
byte[] buy = new byte[1024];
int len=in.read(buy);
//将数据显示在文本区中
ta.append(new String(buy,0,len));
}
catch (Exception e){
throw new RuntimeException("网络"+path+"链接失败");
}
}
public static void main(String[] args) throws Exception{
new MyIEDemo();
}
}
网络编程-小知识点
1,Socket类中空参数的构造函数
通过connect(SocketAddress endpoint)方法来连接服务器,
因为SocketAddress是一个抽象类,他的子类InetSocketAddress实现了IP套接字地址(ip+端口号)。
2,在ServerSocket构造函数:ServerSocket(int port,int backlog)
Backlog标示队列的最大长度即客户端连接服务器的个数。
1, DNS域名解析
当我们在浏览器输入如www.baidu.com主机名时浏览器是如何通过主机名获取该主机ip地址的呢?
解决:
这就需要将主机名翻译成IP地址,即域名解析:DNS
在进行访问的时候,会先在本地的hosts文件(c:\windows\system32\drivers\ect\host)中找对应的映射。若有,则直接返回请求;若无,则到公网的映射列表即DNS中找对应的映射,找到后,将主机名对应的IP地址返回给本机,本机通过这个IP地址找到对应的服务器。
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------详细请查看: http://edu.csdn.net