java开发⽂档协作_Java⽹络编程---分布式⽂件协同编辑器设
计与实现
⽬录:
第⼀部分:Java⽹络编程知识
(⼀)简单的Http请求
⼀般浏览⽹页时,使⽤的时Ip地址,⽽IP(Internet Protocol,互联⽹协议)⽬前主要是IPv4和IPv6.
IP地址是⼀个32位整数,⼀般分成4个⼋位⼆进制,为了⽅便记忆⼀般将⼋位整数换算为⼀个0-255的⼗进制整数。
InetAddressTest
利⽤Http的这些知识就可以实现⼀个多线程下载器,以及爬⾍的基础向web站点发送GET/POST请求:
(1)⼀个简单的多线程下载器
1 import java.*;
2 importjava.io.RandomAccessFile;
3 importjava.io.InputStream;
4 public classDownUtil
5 {
6 //下载路径
7 privateString path;8 //指定下载⽂件存储的位置
9 privateString targetFile;10 //定义使⽤多少线程下载
11 private intthreadNum;12 //定义下载线程对象
13 privateDownThread[] threads;14 //定义下载⽂件的总⼤⼩
15 private intfileSize;16
17 public DownUtil(String path,String target,intthreadNum)18 {19 this.path =path;20 this.targetFile=target;21
this.threadNum=threadNum;22 //初始化threads数组
23 threads=newDownThread[threadNum];24 }25 public void download() throwsException26 {27 URL url =
newURL(path);28 HttpURLConnection conn =(HttpURLConnection) url.openConnection();29
conn.setConnectTimeout(5*1000);30 conn.setRequestMethod("GET");31 conn.setRequestProperty(32 "Accept",33 "image/gift,image/jpeg,image/pjpeg,image/pjpeg"
34 +"application/x-shockwave-flash,application/xaml+xml"
35 +"application/vnd.ms-xpsdocument,application/x-ms-xbap"
36 +"application/x-ms-application,application/vnd.ms-excel"
37 +"application/vnd.ms-powerpoint,application/msword,*/*"
38 );39 conn.setRequestProperty("Accept-Language","zh-CN");40 conn.setRequestProperty("Charset","UTF-8");41
conn.setRequestProperty("Connection","Keep-Alive");42 //获得⽂件⼤⼩
43 fileSize =ContentLength();44 conn.disconnect();45 int currentPartSize=fileSize/threadNum+1;46 RandomAccessFile file = new RandomAccessFile(targetFile,"rw");47 //设置本地⽂件⼤⼩
java编程开发高清pdf48 file.setLength(fileSize);49 file.close();50 for(int i=0;i
53 int startPos = i*currentPartSize;54 //每个线程使⽤⼀个RandomAccessFile下载
55 RandomAccessFile currentPart=new RandomAccessFile(targetFile,"rw");56 //定位线程下载的位置
57 currentPart.seek(startPos);58 //创建下载线程
59 threads[i]=newDownThread(startPos,currentPartSize,currentPart);60 //启动线程
61 threads[i].start();62 }63 }64 //获取下载的完成⽐
65 public doublegetCompleteRate()66 {67 //统计多个线程已经下载的总⼤⼩
68 int sumSize=0;69 for(int i=0;i
78 private intstartPos;79 //当前线程负责下载的⽂件的⼤⼩
80 private intcurrentPartSize;81 //当前线程需要下载⽂件块
82 privateRandomAccessFile currentPart;83 //定义该现场当前已经下载的字节数
84 public intlength;85 public DownThread(int startPos,intcurrentPartSize,RandomAccessFile currentPart)86 {87
this.startPos=startPos;88 this.currentPartSize=currentPartSize;89 this.currentPart=currentPart;90 }91 public voidrun()92 {93 try
94 {95 URL url = newURL(path);96 HttpURLConnection conn =(HttpURLConnection) url.openConne
ction();97
conn.setConnectTimeout(5*1000);98 conn.setRequestMethod("GET");99 conn.setRequestProperty(100 "Accept",101 "image/gift,image/jpeg,image/pjpeg,image/pjpeg"
102 +"application/x-shockwave-flash,application/xaml+xml"
103 +"application/vnd.ms-xpsdocument,application/x-ms-xbap"
104 +"application/x-ms-application,application/vnd.ms-excel"
105 +"application/vnd.ms-powerpoint,application/msword,*/*"
106 );107 conn.setRequestProperty("Accept-Language","zh-CN");108 conn.setRequestProperty("Charset","UTF-8");109 InputStream InputStream();110 //跳过startPos个字节,只下载⾃⼰负责的那部分⽂件
111 inStream.skip(this.startPos);112 byte[] buffer=new byte[1024];113 int hasRead=0;114 //读取⽹络数据,并写⼊⽂件
115 while(length
View Code
(2)发⽣GET/POST请求
1 importjava.URLConnection;
2 importjava.URL;
3 importjava.util.Map;
4 importjava.util.List;5
importjava.io.BufferedReader;6 importjava.io.InputStreamReader;7 importjava.io.PrintWriter;8 classGetPostTest9 {10 /**
11 *想指定URL发送GET请求12 *@paramurl 发送请求的URL13 *@paramparam 请求参数,格式满⾜key=value&key2=value2的形式14 *@returnURL 代表远程资源的响应15 */
16 public staticString sendGet(String url,String param)17 {18 String result = "";19 String urlName=url+"?"+param;20 try
21 {22 URL realUrl=newURL(urlName);23 //打开和URL之间的连接
24 URLConnection conn=realUrl.openConnection();25 //设置通⽤的请求属性
26 conn.setRequestProperty("accept","*/*");27 conn.setRequestProperty("connection","Keep-Alive");28
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");29 //建⽴实际链接
t();31 Map> map =HeaderFields();32 //遍历所有相应头字段
33 for(String key:map.keySet())34 {35 System.out.println(key+"---->"+(key));36 }37 try(38 //定义BufferedReader输⼊流来读取URL响应
39 BufferedReader in = new BufferedReader(new InputStream(),"utf-8")))40 {41 String line;42 while((adLine())!=null)43 {44 result+="\n"+line;45 }46 }47 }48 catch
(Exception e)49 {50 System.out.println("发送GET请求出现异常!"+e);51 e.printStackTrace();52 }53 returnresult;54 }55 /**
56 *想指定URL发送POST请求57 *@paramurl 发送请求的URL58 *@paramparam 请求参数,格式满⾜key=value&key2=value2的形式59 *@returnURL 代表远程资源的响应60 */
61 public staticString sendPost(String url,String param)62 {63 String result="";64 try
65 {66 URL realUrl=newURL(url);67 //打开和URL之间的连接
68 URLConnection conn=realUrl.openConnection();69 //设置通⽤的请求属性
70 conn.setRequestProperty("accept","*/*");71 conn.setRequestProperty("connection","Keep-Alive");72
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");73 conn.setDoOutput(true);74 conn.setDoInput(true);75 try(76 //获取URLConnection对象对应的输出流
77 PrintWriter out =OutputStream()) )78 {79 //发送请求参数
80 out.print(param);81 //flush输出流的缓冲
82 out.flush();83 }84 try(85 //定义BufferedReader输⼊流来读取URL响应
86 BufferedReader in = new BufferedReader(new InputStream(),"utf-8")))87 {88 String line;89 while((adLine())!=null)90 {91 result+="\n"+line;92 }93 }94 }95 catch(Exception e)96 {97 System.out.println("发送POST请求出现异常!"+e);98 e.printStackTrace();99 }100 returnresult;101 }102 public static voidmain(String[] args)103 {104 //String s =GetPostTest.sendGet("www.jd",null);105 //System.out.println(s);
106 String s1=GetPostTest.sendPost("my.just.edu/","user=1245532105&pwd=095493");107 String s2
=GetPostTest.sendGet("my.just.edu/index.portal",null);108 System.out.println(s1);109 }110 }
View Code
(⼆)基于TCP协议的⽹络编程(使⽤Socket进⾏通信)
TCP协议⼀般是和IP协议⼀起使⽤的,TCP/IP协议属于⼀种可靠的⽹络协议,它可以在通信的两端各
建⽴⼀个Socket,使得两端形成⼀个虚拟的⽹络链路。于是两端的程序就可以通过这个虚拟链路进⾏通信。
通过安装IP协议,可以保证计算机之间发送和接受数据,但是⽆法解决数据分组在传输过程中的问题。所以需要TCP协议来提供可靠并且⽆差错的通信服务。
通过java的封装好的Socket可以实现⼀个简单的聊天程序。这个程序由服务端程序和客户端程序组成,为了实现⽤户聊天需要在服务端除了Server⽤于接受客户端请求并建⽴对应的Socket,还得通过⼀个ServerThread来为每个客户端建⽴⼀个线程⽤于监听客户端的消息,并向客户端发送消息。⽽在客户端除了⼀个Client程序⽤于建⽴和服务器端的Socket并且将⽤户输⼊的数据发送给服务器端,还需要⼀个ClientThread⽤来建⽴⼀个线程⽤于监听服务器端发来的数据并显⽰出来。
1 importjava.io.PrintStream;
2 importjava.io.IOException;
3 importjava.ServerSocket;
4 importjava.Socket;
5 importjava.util.List;
6 importjava.util.Collections;
7 importjava.util.ArrayList;
8 importjava.lang.Thread;
9 classMyServer10 {11 public static final int SERVER_PORT=30000;12 //利⽤MyMap保存每个客户端名字和对应的输出流
13 public static MyMap clients = new MyMap();14 public voidinit()15 {16 try
17 (18 //建⽴监听的ServerSocket
19 ServerSocket ss = newServerSocket(SERVER_PORT))20 {21 //采⽤死循环⼀直接受客户端的请求
22 while(true)23 {24 Socket s=ss.accept();25 newMyServerThread(s).start();26 }27 }28 catch(IOExce
ption ex)29 {30 System.out.println("服务器启动失败,请检查端⼝:"+SERVER_PORT+"是否已经被占⽤?");31 }32 }33 public static
voidmain(String[] args)34 {35 MyServer server=newMyServer();36 server.init();37 }38 }
Server
1 importjava.Socket;
2 importjava.io.BufferedReader;
3 importjava.io.IOException;
4 importjava.io.InputStreamReader;
5 importjava.io.PrintStream;
6 public class MyServerThread extendsThread
7 {
8 //定义当前线程所处理的Socket
9 private Socket s=null;10 //该Socket对应的输⼊流
11 BufferedReader br=null;12 //该Socket对应的输出流
13 PrintStream ps=null;14 public MyServerThread(Socket s) throwsIOException15 {16 this.s=s;17 }18 public voidrun()19 {20 try
21 {22 //获取该Socket对应得输⼊流
23 br=new BufferedReader(InputStream()));24 //获取该Socket对应的输出流
25 ps=OutputStream());26 String line = null;27 //采⽤循环不断地从Socket中读取客户端发来的数据
28 while( (adLine())!=null)29 {30 //如果读取到MyProtrocol.USER_ROUND开始,并以其结束则可以确定读到的是⽤户的登录名
31 if(line.startsWith(MyProtocol.USER_ROUND)&&dsWith(MyProtocol.USER_ROUND))32 {33 //得到真实消息
34 String userName=getRealMsg(line);35 //如果⽤户名重复
36 if(MyServer.ainsKey(userName))37 {38 System.out.println("⽤户名重复");39
ps.println(MyProtocol.NAME_REP);40 }41 else
42 {43 System.out.println(userName+"登陆成功");44 ps.println(MyProtocol.LOGIN_SUCCESS);45
MyServer.clients.put(userName,ps);46 }47 }48 //如果读到以MyProtocol.PRIVATE_ROUND开始,并以其结束,则可以确定是私聊信息,私聊信息只向制定输出流发送
49 else if(line.startsWith(MyProtocol.PRIVATE_ROUND)&&dsWith(MyProtocol.PRIVATE_ROUND))50 {51 //得到真实消息
52 String userAndMsg =getRealMsg(line);53 //以SPLIT_SIGN分割,前半部分是私聊⽤户名,后⼀部分是内容54
//System.out.println(userAndMsg);55 //System.out.println(MyProtocol.SPLIT_SIGN);
56 String user = userAndMsg.split(MyProtocol.SPLIT_SIGN)[0];57 String msg = userAndMsg.split(MyProtocol.SPLIT_SIGN) [1];58 //获取私聊⽤户对应的输出流,并发送私聊信息
59 MyServer.(user).println(KeyByValue(ps)+"悄悄对你说:"+msg);60 }61 //公聊,对所有Socket发
62 else
63 {64 //获取真实消息
65 String msg=getRealMsg(line);66 //遍历clients中的每个输出流
67 for(PrintStream clientPs:MyServer.clients.valueSet())68 {69
clientPs.println(KeyByValue(ps)+"说:"+msg);70 }71 }72 }73 }74 //捕获到异常,表明该Socket有问题,将该程序对应的输出流从Map中删除
75 catch(IOException ex)76 {77 veByValue(ps);78 System.out.println(MyServer.clients.map.size());79 //关闭⽹络和IO资源
80 try
81 {82 if(br!=null) br.close();83 if(ps!=null) ps.close();84 if(s!=null) s.close();85 }86 catch(IOException e)87 {88
e.printStackTrace();89 }90 }91 }92 //将读到的内容去掉前后的协议,恢复成真实数据
93 privateString getRealMsg(String line)94 {95 return line.substring(MyProtocol.PROTOCOL_LEN,line.length()-MyProtocol.PROTOCOL_LEN);96 }97 }
ServerThread
1 importjava.io.PrintStream;
2 importjava.io.IOException;
3 importjava.UnknownHostException;4
importjava.io.InputStreamReader;5 importjava.io.BufferedReader;6 importjava.ServerSocket;7 importjava.Socket;8 importjava.InetAddress;9 importjavax.swing.JOptionPane;10 classMyClient11 {12 private static final int
SERVER_PORT=30000;13 privateSocket socket;14 privatePrintStream ps;15 privateBufferedReader brServer;16 privateBufferedReader keyIn;17 public voidinit()18 {19 try
20 {21 //初始化代表键盘的输⼊流
22 keyIn = new BufferedReader(newInputStreamReader(System.in));23 //链接到服务器
24 socket = new Socket("127.0.0.1",SERVER_PORT);25 //获取该Socket对应的输⼊流和输出流
26 ps = OutputStream());27 brServer=new
BufferedReader(InputStream()));28 String tip="";29 //采⽤循环不断弹出对话框要求输⼊⽤户名
30 while(true)31 {32 String userName=JOptionPane.showInputDialog(tip+"输⼊⽤户名");33 //⽤户输⼊⽤户名后前后加上协议字符串后发送
34 ps.println(MyProtocol.USER_ROUND+userName+MyProtocol.USER_ROUND);35 //读取服务器的响应
36 String result =adLine();37 //如果⽤户名重复则开始下次循环
38 if(result.equals(MyProtocol.NAME_REP))39 {40 tip="⽤户名重复,请重试!";41 continue;42 }43 //如果服务器返回登陆成功,则循环结束
44 if(result.equals(MyProtocol.LOGIN_SUCCESS))45 {46 break;47 }48 }49 }50 //补货到异常,关闭⽹络资源,并推出程序
51 catch(UnknownHostException ex)52 {53 System.out.println("不到远程服务器,请确定服务器已经启动!");54 closeRs();it(1);56 }57 catch(IOException ex)58 {59 System.out.println("⽹络异常!请重新登陆");60 closeRs();61
64 newMyClientThread(brServer).start();65 }66 //定义⼀个读取键盘输出,并向⽹络发送的⽅法
67 private voidreadAndSend()68 {69 try
70 {71 //不断地读取键盘的输⼊
72 String line=null;73 while((adLine())!=null)74 {75 //如果发送的信息中有冒号,并且以//开头,则认为发送私聊信息
76 if(line.indexOf(":")>0&&line.startsWith("//"))77 {78 line=line.substring(2);79
//System.out.println(MyProtocol.PRIVATE_ROUND+line.split(":")[0]+MyProtocol.SPLIT_SIGN+line.split(":")
[1]+MyProtocol.PRIVATE_ROUND);
80 ps.println(MyProtocol.PRIVATE_ROUND+line.split(":")[0]+MyProtocol.SPLIT_SIGN+line.split(":")
[1]+MyProtocol.PRIVATE_ROUND);81 }82 else
83 {84 ps.println(MyProtocol.MSG_ROUND+line+MyProtocol.MSG_ROUND);85 }86 }87 }88 //捕获到异常,关闭⽹络资源,并退出程序
89 catch(IOException ex)90 {91 System.out.println("⽹络异常!请重新登陆");92 closeRs();it(1);94 }95 }96 //关闭Socket、输⼊流、输出流的⽅法
97 private voidcloseRs()98 {99 try

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。