目录:

第一部分:Java网络编程知识

(一)简单的Http请求

  一般浏览网页时,使用的时Ip地址,而IP(Internet Protocol,互联网协议)目前主要是IPv4和IPv6.

  IP地址是一个32位整数,一般分成4个八位二进制,为了方便记忆一般将八位整数换算为一个0-255的十进制整数。

 InetAddressTest

  利用Http的这些知识就可以实现一个多线程下载器,以及爬虫的基础向web站点发送GET/POST请求:

  (1)一个简单的多线程下载器

 import java.net.*;
import java.io.RandomAccessFile;
import java.io.InputStream;
public class DownUtil
{
//下载路径
private String path;
//指定下载文件存储的位置
private String targetFile;
//定义使用多少线程下载
private int threadNum;
//定义下载线程对象
private DownThread[] threads;
//定义下载文件的总大小
private int fileSize; public DownUtil(String path,String target,int threadNum)
{
this.path = path;
this.targetFile=target;
this.threadNum=threadNum;
//初始化threads数组
threads=new DownThread[threadNum];
}
public void download() throws Exception
{
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gift,image/jpeg,image/pjpeg,image/pjpeg"
+"application/x-shockwave-flash,application/xaml+xml"
+"application/vnd.ms-xpsdocument,application/x-ms-xbap"
+"application/x-ms-application,application/vnd.ms-excel"
+"application/vnd.ms-powerpoint,application/msword,*/*"
);
conn.setRequestProperty("Accept-Language","zh-CN");
conn.setRequestProperty("Charset","UTF-8");
conn.setRequestProperty("Connection","Keep-Alive");
//获得文件大小
fileSize = conn.getContentLength();
conn.disconnect();
int currentPartSize=fileSize/threadNum+1;
RandomAccessFile file = new RandomAccessFile(targetFile,"rw");
//设置本地文件大小
file.setLength(fileSize);
file.close();
for(int i=0;i<threadNum;i++)
{
//计算每个线程开始的位置
int startPos = i*currentPartSize;
//每个线程使用一个RandomAccessFile下载
RandomAccessFile currentPart=new RandomAccessFile(targetFile,"rw");
//定位线程下载的位置
currentPart.seek(startPos);
//创建下载线程
threads[i]=new DownThread(startPos,currentPartSize,currentPart);
//启动线程
threads[i].start();
}
}
//获取下载的完成比
public double getCompleteRate()
{
//统计多个线程已经下载的总大小
int sumSize=0;
for(int i=0;i<threadNum;i++)
{
sumSize+=threads[i].length;
}
return sumSize*1.0/fileSize;
}
private class DownThread extends Thread
{
//当前的下载位置
private int startPos;
//当前线程负责下载的文件的大小
private int currentPartSize;
//当前线程需要下载文件块
private RandomAccessFile currentPart;
//定义该现场当前已经下载的字节数
public int length;
public DownThread(int startPos,int currentPartSize,RandomAccessFile currentPart)
{
this.startPos=startPos;
this.currentPartSize=currentPartSize;
this.currentPart=currentPart;
}
public void run()
{
try
{
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gift,image/jpeg,image/pjpeg,image/pjpeg"
+"application/x-shockwave-flash,application/xaml+xml"
+"application/vnd.ms-xpsdocument,application/x-ms-xbap"
+"application/x-ms-application,application/vnd.ms-excel"
+"application/vnd.ms-powerpoint,application/msword,*/*"
);
conn.setRequestProperty("Accept-Language","zh-CN");
conn.setRequestProperty("Charset","UTF-8");
InputStream inStream=conn.getInputStream();
//跳过startPos个字节,只下载自己负责的那部分文件
inStream.skip(this.startPos);
byte[] buffer=new byte[1024];
int hasRead=0;
//读取网络数据,并写入文件
while(length<currentPartSize && (hasRead=inStream.read(buffer))!=-1)
{
currentPart.write(buffer,0,hasRead);
length+=hasRead;
}
currentPart.close();
inStream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

  (2)发生GET/POST请求

 import java.net.URLConnection;
import java.net.URL;
import java.util.Map;
import java.util.List;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
class GetPostTest
{
/**
*想指定URL发送GET请求
*@param url 发送请求的URL
*@param param 请求参数,格式满足key=value&key2=value2的形式
*@return URL 代表远程资源的响应
*/
public static String sendGet(String url,String param)
{
String result = "";
String urlName=url+"?"+param;
try
{
URL realUrl=new URL(urlName);
//打开和URL之间的连接
URLConnection conn=realUrl.openConnection();
//设置通用的请求属性
conn.setRequestProperty("accept","*/*");
conn.setRequestProperty("connection","Keep-Alive");
conn.setRequestProperty("user-agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2906.0 Safari/537.36");
//建立实际链接
conn.connect();
Map<String,List<String>> map =conn.getHeaderFields();
//遍历所有相应头字段
for(String key:map.keySet())
{
System.out.println(key+"---->"+map.get(key));
}
try(
//定义BufferedReader输入流来读取URL响应
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8")))
{
String line;
while((line=in.readLine())!=null)
{
result+="\n"+line;
}
}
}
catch (Exception e)
{
System.out.println("发送GET请求出现异常!"+e);
e.printStackTrace();
}
return result;
}
/**
*想指定URL发送POST请求
*@param url 发送请求的URL
*@param param 请求参数,格式满足key=value&key2=value2的形式
*@return URL 代表远程资源的响应
*/
public static String sendPost(String url,String param)
{
String result="";
try
{
URL realUrl=new URL(url);
//打开和URL之间的连接
URLConnection conn=realUrl.openConnection();
//设置通用的请求属性
conn.setRequestProperty("accept","*/*");
conn.setRequestProperty("connection","Keep-Alive");
conn.setRequestProperty("user-agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2906.0 Safari/537.36");
conn.setDoOutput(true);
conn.setDoInput(true);
try(
//获取URLConnection对象对应的输出流
PrintWriter out =new PrintWriter(conn.getOutputStream()) )
{
//发送请求参数
out.print(param);
//flush输出流的缓冲
out.flush();
}
try(
//定义BufferedReader输入流来读取URL响应
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8")))
{
String line;
while((line=in.readLine())!=null)
{
result+="\n"+line;
}
}
}
catch (Exception e)
{
System.out.println("发送POST请求出现异常!"+e);
e.printStackTrace();
}
return result;
}
public static void main(String[] args)
{
//String s =GetPostTest.sendGet("https://www.jd.com",null);
//System.out.println(s);
String s1=GetPostTest.sendPost("http://my.just.edu.cn/","user=1245532105&pwd=095493");
String s2 =GetPostTest.sendGet("http://my.just.edu.cn/index.portal",null);
System.out.println(s1);
}
}

(二)基于TCP协议的网络编程(使用Socket进行通信)

  TCP协议一般是和IP协议一起使用的,TCP/IP协议属于一种可靠的网络协议,它可以在通信的两端各建立一个Socket,使得两端形成一个虚拟的网络链路。于是两端的程序就可以通过这个虚拟链路进行通信。

  通过安装IP协议,可以保证计算机之间发送和接受数据,但是无法解决数据分组在传输过程中的问题。所以需要TCP协议来提供可靠并且无差错的通信服务。

  通过java的封装好的Socket可以实现一个简单的聊天程序。这个程序由服务端程序和客户端程序组成,为了实现用户聊天需要在服务端除了Server用于接受客户端请求并建立对应的Socket,还得通过一个ServerThread来为每个客户端建立一个线程用于监听客户端的消息,并向客户端发送消息。而在客户端除了一个Client程序用于建立和服务器端的Socket并且将用户输入的数据发送给服务器端,还需要一个ClientThread用来建立一个线程用于监听服务器端发来的数据并显示出来。

 import java.io.PrintStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;
import java.lang.Thread;
class MyServer
{
public static final int SERVER_PORT=30000;
//利用MyMap保存每个客户端名字和对应的输出流
public static MyMap<String,PrintStream> clients = new MyMap<String,PrintStream>();
public void init()
{
try
(
//建立监听的ServerSocket
ServerSocket ss = new ServerSocket(SERVER_PORT))
{
//采用死循环一直接受客户端的请求
while(true)
{
Socket s= ss.accept();
new MyServerThread(s).start();
}
}
catch (IOException ex)
{
System.out.println("服务器启动失败,请检查端口:"+SERVER_PORT+"是否已经被占用?");
}
}
public static void main(String[] args)
{
MyServer server=new MyServer();
server.init();
}
}

Server

 import java.net.Socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
public class MyServerThread extends Thread
{
//定义当前线程所处理的Socket
private Socket s=null;
//该Socket对应的输入流
BufferedReader br=null;
//该Socket对应的输出流
PrintStream ps=null;
public MyServerThread(Socket s) throws IOException
{
this.s=s;
}
public void run()
{
try
{
//获取该Socket对应得输入流
br=new BufferedReader(new InputStreamReader(s.getInputStream()));
//获取该Socket对应的输出流
ps=new PrintStream(s.getOutputStream());
String line = null;
//采用循环不断地从Socket中读取客户端发来的数据
while( (line=br.readLine())!=null)
{
//如果读取到MyProtrocol.USER_ROUND开始,并以其结束则可以确定读到的是用户的登录名
if(line.startsWith(MyProtocol.USER_ROUND)&&line.endsWith(MyProtocol.USER_ROUND))
{
//得到真实消息
String userName=getRealMsg(line);
//如果用户名重复
if(MyServer.clients.map.containsKey(userName))
{
System.out.println("用户名重复");
ps.println(MyProtocol.NAME_REP);
}
else
{
System.out.println(userName+"登陆成功");
ps.println(MyProtocol.LOGIN_SUCCESS);
MyServer.clients.put(userName,ps);
}
}
//如果读到以MyProtocol.PRIVATE_ROUND开始,并以其结束,则可以确定是私聊信息,私聊信息只向制定输出流发送
else if(line.startsWith(MyProtocol.PRIVATE_ROUND)&&line.endsWith(MyProtocol.PRIVATE_ROUND))
{
//得到真实消息
String userAndMsg = getRealMsg(line);
//以SPLIT_SIGN分割,前半部分是私聊用户名,后一部分是内容
//System.out.println(userAndMsg);
//System.out.println(MyProtocol.SPLIT_SIGN);
String user = userAndMsg.split(MyProtocol.SPLIT_SIGN)[0];
String msg = userAndMsg.split(MyProtocol.SPLIT_SIGN)[1];
//获取私聊用户对应的输出流,并发送私聊信息
MyServer.clients.map.get(user).println(MyServer.clients.getKeyByValue(ps)+"悄悄对你说:"+msg);
}
//公聊,对所有Socket发
else
{
//获取真实消息
String msg=getRealMsg(line);
//遍历clients中的每个输出流
for(PrintStream clientPs:MyServer.clients.valueSet())
{
clientPs.println(MyServer.clients.getKeyByValue(ps)+"说:"+msg);
}
}
}
}
//捕获到异常,表明该Socket有问题,将该程序对应的输出流从Map中删除
catch (IOException ex)
{
MyServer.clients.removeByValue(ps);
System.out.println(MyServer.clients.map.size());
//关闭网络和IO资源
try
{
if(br!=null) br.close();
if(ps!=null) ps.close();
if(s!=null) s.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
//将读到的内容去掉前后的协议,恢复成真实数据
private String getRealMsg(String line)
{
return line.substring(MyProtocol.PROTOCOL_LEN,line.length()-MyProtocol.PROTOCOL_LEN);
}
}

ServerThread

 import java.io.PrintStream;
import java.io.IOException;
import java.net.UnknownHostException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.InetAddress;
import javax.swing.JOptionPane;
class MyClient
{
private static final int SERVER_PORT=30000;
private Socket socket;
private PrintStream ps;
private BufferedReader brServer;
private BufferedReader keyIn;
public void init()
{
try
{
//初始化代表键盘的输入流
keyIn = new BufferedReader(new InputStreamReader(System.in));
//链接到服务器
socket = new Socket("127.0.0.1",SERVER_PORT);
//获取该Socket对应的输入流和输出流
ps = new PrintStream(socket.getOutputStream());
brServer=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String tip="";
//采用循环不断弹出对话框要求输入用户名
while(true)
{
String userName=JOptionPane.showInputDialog(tip+"输入用户名");
//用户输入用户名后前后加上协议字符串后发送
ps.println(MyProtocol.USER_ROUND+userName+MyProtocol.USER_ROUND);
//读取服务器的响应
String result = brServer.readLine();
//如果用户名重复则开始下次循环
if(result.equals(MyProtocol.NAME_REP))
{
tip="用户名重复,请重试!";
continue;
}
//如果服务器返回登陆成功,则循环结束
if(result.equals(MyProtocol.LOGIN_SUCCESS))
{
break;
}
}
}
//补货到异常,关闭网络资源,并推出程序
catch (UnknownHostException ex)
{
System.out.println("找不到远程服务器,请确定服务器已经启动!");
closeRs();
System.exit(1);
}
catch(IOException ex)
{
System.out.println("网络异常!请重新登陆");
closeRs();
System.exit(1);
}
//以该socket对应的输入流启动Client线程
new MyClientThread(brServer).start();
}
//定义一个读取键盘输出,并向网络发送的方法
private void readAndSend()
{
try
{
//不断地读取键盘的输入
String line=null;
while((line=keyIn.readLine())!=null)
{
//如果发送的信息中有冒号,并且以//开头,则认为发送私聊信息
if(line.indexOf(":")>0&&line.startsWith("//"))
{
line=line.substring(2);
//System.out.println(MyProtocol.PRIVATE_ROUND+line.split(":")[0]+MyProtocol.SPLIT_SIGN+line.split(":")[1]+MyProtocol.PRIVATE_ROUND);
ps.println(MyProtocol.PRIVATE_ROUND+line.split(":")[0]+MyProtocol.SPLIT_SIGN+line.split(":")[1]+MyProtocol.PRIVATE_ROUND);
}
else
{
ps.println(MyProtocol.MSG_ROUND+line+MyProtocol.MSG_ROUND);
}
}
}
//捕获到异常,关闭网络资源,并退出程序
catch (IOException ex)
{
System.out.println("网络异常!请重新登陆");
closeRs();
System.exit(1);
}
}
//关闭Socket、输入流、输出流的方法
private void closeRs()
{
try
{
if(keyIn!=null) ps.close();
if(brServer!=null) brServer.close();
if(ps!=null) ps.close();
if(socket!=null) keyIn.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args)
{
MyClient client=new MyClient();
client.init();
client.readAndSend();
}
}

Client

 import java.io.PrintStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.InetAddress;
import java.lang.Thread;
class MyClientThread extends Thread
{
//该客户端线程负责处理输入流
BufferedReader br=null;
public MyClientThread(BufferedReader br)
{
this.br=br;
}
public void run()
{
try
{
String line=null;
//不断的读取Socket输入流的内容,并将其打印输出
while((line=br.readLine())!=null)
{
System.out.println(line);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if(br!=null) br.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}

ClientThread

  JDK1.4开始,Java提供了NIO API用于开发高性能的网络服务器,借助NIO可以不必为每个客户端都建立一个线程。下面我将利用NIO改变这个聊天程序。

第二部分:分布式文件协同编辑器

第一部分 Java网络编程知识

  

附件:《实验指导报告书》

分布式文件协同编辑器

实验指导书--1

 

一、实验目的

加深对分布式系统基本概念的理解,灵活运用多种分布式互斥与同步访问的算法;掌握网络编程的基本方法,熟悉Socket套接字的使用,实现网络间的通信程序;设计并初步实现一个“分布式文件协同编辑器”原型系统。

二、实验要求

1、有N个网络用户编辑同一磁盘上的多个文件,文件的存取服务由文件服务器完成,网络上的用户通过客户端软件完成协同编辑工作。编辑器架构如图1所示:

 
   

2、设计并实现分布式互斥与同步访问,实现多用户协同编辑。

3、设计并初步实现一个“分布式文件协同编辑器”。

4、可以在Window或Linux下完成。

三、实验内容

实验内容由两部分组成:

第一部分:编写文件服务器程序,详细要求有:

  1. 实现对磁盘文件的存取服务。
  2. 实现与客户端软件的文件传输服务(客户端指定文件名称,通过Socket实现)
  3. 不能使用集中控制策略。

第二部分:编写客户端软件,具体要求如下:

  1. 实现对文件简单的编辑/浏览功能(只要能查看/改变文件内容即可);
  2. 实现与文件服务器的文件传输功能(客户端指定文件名称,通过Socket实现);
  3. 实现多个客户端软件之间的通讯功能,能实现协同工作的功能;
  4. 实现分布式的互斥编辑功能。

四、实验方法

1、实验有两个方案(同学们也可自己设计新的方案):

方案一:获取并发用户列表的方法:客户端软件在访问文件时,先在子网内广播信息,访问该文件的其它客户端软件应答。

方案二:分布式互斥访问可以使用令牌环算法。

2、实现分布式互斥编辑功能(同学们也可自己设计新的方案):

1)        多个客户可以同时浏览文件内容(已经提交的版本)。

2)        当文件加互斥锁时,多个客户也可以同时浏览文件内容(旧版本),但是只能由加互斥锁的用户编辑文件(未提交的版本),而且提交之后,必须通知其他浏览该文件的用户,以便其它用户获得最新版本的内容。

3)        进入编辑状态之前,首先要获得互斥锁。而且在任意时刻,只能一个用户对文件进行编辑。

Java 网络编程---分布式文件协同编辑器设计与实现的更多相关文章

  1. 20145212 实验五《Java网络编程》

    20145212 实验五<Java网络编程> 一.实验内容 1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成 ...

  2. 20145213《Java程序设计》实验五Java网络编程及安全

    20145213<Java程序设计>实验五Java网络编程及安全 实验内容 1.掌握Socket程序的编写. 2.掌握密码技术的使用. 3.设计安全传输系统. 实验预期 1.客户端与服务器 ...

  3. 20145206《Java程序设计》实验五Java网络编程及安全

    20145206<Java程序设计>实验五 Java网络编程及安全 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验步骤 我和201451 ...

  4. 20145337实验五Java网络编程及安全

    20145337实验五Java网络编程及安全 实验内容 掌握Socket程序的编写 掌握密码技术的使用 设计安全传输系统 实验步骤 基于Java Socket实现安全传输 基于TCP实现客户端和服务器 ...

  5. Java 网络编程----基本概念

    网络现在是一个非常普遍的概念. 以下是维基百科上的解释: 网络一词有多种意义,可解作: 网络流也简称为网络(network).一般用于管道系统.交通系统.通讯系统建模. 有时特指计算机网络. 或特指其 ...

  6. 20145208 实验五 Java网络编程

    20145208 实验五 Java网络编程 实验内容 1.用书上的TCP代码,实现服务器与客户端. 2.客户端与服务器连接 3.客户端中输入明文,利用DES算法加密,DES的秘钥用RSA公钥密码中服务 ...

  7. 20145215实验五 Java网络编程及安全

    20145215实验五 Java网络编程及安全 实验内容 掌握Socket程序的编写: 掌握密码技术的使用: 设计安全传输系统. 实验步骤 本次实验我的结对编程对象是20145208蔡野,我负责编写客 ...

  8. Java实验报告五:Java网络编程及安全

    Java实验报告五:Java网络编程及安全                                                                               ...

  9. 20145211 《Java程序设计》实验报告五————Java网络编程及安全实验报告

    实验内容 1.掌握Socket程序的编写: 掌握密码技术的使用: 设计安全传输系统. 实验步骤 这一部分是与我的partner合作的,详见他的博客- [20145326 <Java程序设计> ...

随机推荐

  1. cf C. Insertion Sort

    http://codeforces.com/contest/362/problem/C #include <cstdio> #include <cstring> #includ ...

  2. Codeforces 459E Pashmak and Graph

    http://www.codeforces.com/problemset/problem/459/E 题意: 给出n个点,m条边的有向图,每个边有边权,求一条最长的边权上升的路径的长度. 思路:用f存 ...

  3. Row Cache Objects

    This latch comes into play when user processes are attempting to access or update the cached data di ...

  4. Android SQLite简介

    SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且只利用很少的内存就有很好的性能.此外它还是开源的,任何人都可以使用它.许多开源项目((Mozilla, PHP, Python)都使 ...

  5. 前端HTML与CSS编码规范

    HTML 语法 HTML5 doctype 语言属性(Language attribute) 字符编码 IE 兼容模式 引入 CSS 和 JavaScript 文件 实用为王 属性顺序 布尔(bool ...

  6. 跨平台utf8转unicode研究实现(2)

    最近在用VC++开发一个小工具,平时用惯了.NET,用起VC++最郁闷的就是字符串处理.当然最最让人难于琢磨的就是字符集,编码之间的转换.通过这几天的研究,终于明白了Unicode和UTF-8之间编码 ...

  7. c语言中break continue goto return和exit的区别 联系(筛选奇数和goto求和)

    break 一般你是用于循环和switch语句中,执行break,退出循环,如果是多层循环,那么退出的当前的循环. 如果循环结构中有switch语句,而switch语句中有break 那么不会直接退出 ...

  8. Java中的XML操作

    1.DOM方式解析(读取)XML文件 待解析(读取)的XML文件,直接放在项目根目录下即可 <?xml version="1.0" encoding="UTF-8& ...

  9. Android Studio编译好的apk放在哪里?

    Eclipse中编译好的apk文件时在bin文件中面的,可是在Android Studio有一个比較大的修改了,编译好的apk在android studio里面是直接看不到了,并且apk文件所在文件夹 ...

  10. IT痴汉的工作现状25-技术之养成

    要想成为技术大牛,除了天赋以外,更与后天的刻苦努力分不开.伟仔我天生愚顿.工作多年后仍与大牛相差甚远,更加觉得技术的养成是一个异常困难的过程. 是我不用功吗?我不这样觉得.伟仔尽管是个懒人,但对于技术 ...