------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
网络编程
客户端服务端的原理:
生活中:
常见的客户端:浏览器:IE
常见的服务端:服务器:tomcat
一、自定义服务端:
客户端使用电脑上的浏览器即可;
1. 了解一下客户端向服务端发送的请求
import java.io.*;
import java.net.*;
class MyServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(6060);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+"已连接");
InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
//反馈信息
PrintWriter pW = new PrintWriter(s.getOutputStream(),true);
pW.println("欢迎光临");
s.close();
ss.close();
}
}
result:
发送的数据(请求)为:
127.0.0.1已连接
GET / HTTP/1.1
Host: 127.0.0.1:6060
Connection: keep-alive
Cache-Control: max-age=0
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/31.0.1650.63 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8
2. 模拟一个浏览器获取信息
import java.io.*;
import java.net.*;
class MyBrowser
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",80);
//模拟浏览器向Tomcat服务器反射http协议的请求消息
PrintWriter pW = new PrintWriter(s.getOutputStream(),true);
pW.println("GET /MyBrowser.html HTTP/1.1");
pW.println("Accept:*/*");
pW.println("Host:127.0.0.1:8080");
pW.println("Connection:close");
pW.println("");
InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
s.close();
}
}
result:
二、URL&URLConnection
URI:统一资源标示符
URL:统一资源定位符,也就是说根据URL能够定位到网络上上的某个资源,它是指向互联网资源的指针。
每个URL都是URI,但是不一定每个URI都是URL。URI还包括URN(统一资源名称),它命名资源但不指定如何定位资源。
示例:
import java.io.*;
import java.net.*;
class URLDemo
{
public static void main(String[] args) throws Exception
{
String str = "http://localhost/MyBrowser.html";
URL url = new URL(str);
sop("getProtocol:"+url.getProtocol());
sop("getHost:"+url.getHost());
sop("getPort:"+url.getPort());
sop("getFile:"+url.getFile());
sop("getPath:"+url.getPath());
sop("getQuery:"+url.getQuery());
InputStream is = url.openStream();//相当于url.openConnection().getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
String text = new String(buf,0,len);
sop(text);
is.close();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
result:
示例:URlConnection
import java.net.*;
class URLDemo1
{
public static void main(String[] args) throws Exception
{
String str = "http://localhost/MyBrowser.html";
URL url = new URL(str);
//获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议对象+socket
URLConnection conn = url.openConnection();
System.out.println(conn);
System.out.println("----------------------");
//由于URLConnection对象已经把相应头给解析了,所以可以通过URLconnection对象获取响应头某属性名对应的属性值
String value = conn.getHeaderField("Content-Type");
System.out.println(value);
}
}
result:
常见网络结构:
1. C/S client/server
特点:客户端,服务端都要开发 开发成本高,维护麻烦
好处:客户端可以在本地分担一些任务,减轻服务端的压力
2. B/s browser/server
特点:只要开发服务端,客户端用浏览器代替,开发成本较低,维护简单
缺点:所有运算在服务端,服务端压力大
练习:TCP协议上传图片客户端和服务端
import java.io.*;
import java.net.*;
class TCPServerDemo
{
public static void main(String[] args) throws Exception
{
System.out.println("-------1------");
ServerSocket ss = new ServerSocket (10001);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"------已连接");
InputStream is = s.getInputStream();
File filePath = new File(ip+".jpg");
FileOutputStream fos = new FileOutputStream(filePath);
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf))!=-1){
fos.write(buf,0,len);
}
System.out.println("-------2------");
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
ss.close();
}
}
class TCPClientDemo
{
public static void main(String[] args)throws Exception{
Socket s = new Socket("127.0.0.1",10001);
FileInputStream fis = new FileInputStream("1.jpg");
OutputStream out = s.getOutputStream();
System.out.println("-------1------");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!=-1){
out.write(buf,0,len);
}
System.out.println("-------2------");
s.shutdownOutput();
System.out.println("-------3------");
InputStream is = s.getInputStream();
len = is.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
fis.close();
s.close();
}
}
result:
客户端
服务端
拓展:
/*
思想:服务器CPU分配给每条线程的时间片是相同的,即服务器的带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢到越多的服务器资源。
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class MulThreadDown {
static int ThreadCount = 3;//能开启线程数为3个
static int finishedThread = 0;
static String path = "http://............";//这里写上下载的路径地址
public static void main(String[] args) {
//发送get请求,请求这个地址的资源
try {
String fileName = "lol游戏压缩包.zip"
//传入地址,创建URL对象
URL url = new URL(path);
//开启网络连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置get请求
conn.setRequestMethod("GET");
//设置连接延迟5s和读取文件延迟5s
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//如果返回码为200,说明连接建立
if(conn.getResponseCode() == 200){
//拿到所请求资源文件的长度
int length = conn.getContentLength();
File file = new File(fileName);
//生成临时文件,即要下载的资源要存储到这个文件中去
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
//设置临时文件的大小
raf.setLength(length);
raf.close();
//计算出每个线程应该下载多少字节
//每个线程应该是平均分要下载的资源大小,注意:最后一个线程要下载剩余全部的文件
int size = length / ThreadCount;
for (int i = 0; i < ThreadCount; i++) {//i代表开启了第几个线程
//计算线程下载的开始位置和结束位置
int startIndex = i * size;
int endIndex = (i + 1) * size - 1;
//如果是最后一个线程,下载剩下的全部文件
if(i == ThreadCount - 1){
endIndex = length - 1;
}
new DownLoadThread(startIndex, endIndex, i).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class DownLoadThread extends Thread{
int startIndex;//每个线程开始下载文件的位置
int endIndex;//每个线程下载的文件的结束位置
int threadId;//线程ID
public DownLoadThread(int startIndex, int endIndex, int threadId) {
super();
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run() {
//再次发送http请求,下载原文件
try {
File progressFile = new File(threadId + ".txt");
//判断进度临时文件是否存在
if(progressFile.exists()){
FileInputStream fis = new FileInputStream(progressFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
//从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
startIndex += Integer.parseInt(br.readLine());
fis.close();
}
HttpURLConnection conn;
URL url = new URL(MulThreadDown.path);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//通过HTTP请求头中的“Range”这个字段,设置本次http请求所请求的数据的区间
conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
//请求部分数据,相应码是206,如果返回了206,说明下载连接成功
if(conn.getResponseCode() == 206){
//流里此时只有1/3原文件的数据
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
int total = 0;
//拿到临时文件的输出流
File file = new File(fileName);
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
//把文件的写入位置移动至startIndex,断点续传
raf.seek(startIndex);
while((len = is.read(b)) != -1){
//每次读取流里数据之后,同步把数据写入临时文件
raf.write(b, 0, len);
total += len;
//生成一个专门用来记录下载进度的临时文件
RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
//每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
progressRaf.write((total + "").getBytes());
progressRaf.close();
}
raf.close();
MulThreadDown.finishedThread++;
synchronized (MulThreadDown.path) {
if(MulThreadDown.finishedThread == MulThreadDown.ThreadCount){
//如果下载完成线程数为设置的结束线程数,则下载完成,删除临时文件
for (int i = 0; i < MulThreadDown.ThreadCount; i++) {
File f = new File(i + ".txt");
f.delete();
}
MulThreadDown.finishedThread = 0;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
本文深入探讨了Java中的网络编程,包括自定义服务端的实现,了解客户端向服务端发送请求的过程,并模拟浏览器获取信息。进一步讲解了URL和URLConnection的概念及其在网络结构中的应用,区分了URI与URL的差异,并给出了相关示例。同时,文章讨论了C/S和B/S架构的特点和优缺点。最后,提供了TCP协议上传图片的客户端和服务端练习。

1519

被折叠的 条评论
为什么被折叠?



