一、网络编程的概念
1、什么是计算机网络?
把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便的互相产地消息,共享硬件、软件、数据信息等资源。
2、网络通讯协议
- 要使计算机连成的网络能够互通信息,需要对数据传输速率、传输代码、代码结构、传输控制步骤、出错控制等制定一组标准,这一组共同遵守的通信标准就是网络通讯协议,不同的计算机之间必须使用相同的通讯协议才能通讯。
- 在Intent中TCP/IP协议使使用最广泛的通讯协议。TCP/IP的全称是Trasmission Control Protocol/Intnet Protocol。即“传输控制协议/网际协议”。
OSI的七层模型与TCP/IP四层模型
OSI | 对应功能 | TCP/IP |
---|---|---|
应用 | 处理网络应用 | 应用 |
表示 | 数据表示 | 应用 |
会话 | 主机间通信 | 应用 |
传输 | 端到端的链接 | 传输 |
网络 | 寻址和最短路径 | 网络 |
数据链路 | 介质访问(提供通讯路线) | 物理+数据链路 |
物理 | 二进制传输 | 物理+数据链路 |
3、TCP/IP协议
- 是专门设计用于在不可靠的因特网上提供可靠得到、端到端的字节流通信协议。
- 如果IP数据包中有已经封装好的TCP数据包,那么IP将把他们向上传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路之间的连接(通过三次握手实现)。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
- TCP是一种面向连接的通信协议。TCP连接提供两台计算机之间的可靠的无差错的字节流数据传输。
4、获取IP地址:
1、InetAddress.getLocalHost():获取本机的IP地址对象
InetAddress inetAddress=InetAddress.getLocalHost();
System.out.println("inetAddress="+inetAddress);//dell-PC/169.254.246.148
2、根据IP地址对象获取IP地址字符串
String strIP=inetAddress.getHostAddress();
3、获取本机的主机名
String hostName=inetAddress.getHostName();
System.out.println("hostName="+hostName);
4、获取指定主机的IP地址对象
InetAddress address=InetAddress.getByName("10.31.157.74");
System.out.println("address="+address);// /10.31.157.74
5、根据IP地址对象获取IP地址字符串
strIP=address.getHostAddress();
6、获取本机的主机名
hostName=address.getHostName();
5、URL(Uniform Resource Location):统一资源定位符,用来唯一确定网络上的的网站位置的,即网址.
String path=“http://www.baidu.com/hsj/wcf/qq/index.html#qq?userName=admin&pwd=123”;
- http:协议
- www.baidu.com:域名
- /hsj/wcf/qq/index.html:网址的相对路径
- ?分割网址的相对路径和参数的
- userName=admin&pwd=123:如果需要传递多个参数,需要使用&进行连接,每个参数的格式都是key=value
1.实例化统一资源定位符
URL url=new URL(path);
2、得到协议部分
String protocol=url.getProtocol();
System.out.println("protocol="+protocol);//http
3、得到域名部分
String host=url.getHost();
System.out.println("host="+host);//www.baidu.com
4、得到端口号,如果未设置端口则返回-1
int port=url.getPort();
System.out.println("port="+port);//80
5、得到默认端口
port=url.getDefaultPort();
System.out.println("port="+port);
6、得到相对路径
String localPath=url.getPath();
System.out.println("localPath="+localPath);///hsj/wcf/qq/index.html
7、获取锚点
String ref=url.getRef();
System.out.println("ref="+ref);//qq?userName=admin&pwd=123
8、得到询问部分
String query=url.getQuery();
System.out.println("query="+query);//userName=admin&pwd=123
String file=url.getFile();
System.out.println("file="+file);// /hsj/wcf/qq/index.html
二、TCP
(一)、基于TCP协议服务器编程的步骤:
1.实例化监听套接字(ServerSocket)对象,并指定监听的端口号,监听套接字负责监听
serverSocket=new ServerSocket(8000);
2.调用监听套接字的accept()方法等待客户端的连接,如果没有客户端连接过来,则这个方法被阻塞,直到有客户端连接过来,则这个方法解除阻塞状态并返回一个通讯套接字。这时监听套接字的任务就算完成
socket= serverSocket.accept();
//得到客户端的IP地址
String clientIP=socket.getInetAddress().getHostAddress();
//得到客户端的端口号
int clientPort=socket.getPort();
3.通过通讯套接字得到输入流和输出流对象完成读写功能。
InputStream inputStream=socket.getInputStream();//得到输入流目的是读取客户端发送过来的数据
OutputStream outputStream=socket.getOutputStream();//得到输出流目的是向客户端发送数据
4.使用输入流对象读取客户端发送过来的数据
byte[] buffer=new byte[1024];
int len=0;
StringBuilder stringBuilder=new StringBuilder();
//如果没有收到读取结束的标识符,则这个方法一直读取数据,如果读取不到则被阻塞.
while((len=inputStream.read(buffer))!=-1){
stringBuilder.append(new String(buffer,0,len));
}
5、将客户端发送过来的数据进行翻转后重新回送到客户端
stringBuilder=stringBuilder.reverse();
//回送到客户端
outputStream.write(stringBuilder.toString().getBytes());
//告诉客户端我已经写完了(向客户端写出一个结束标记)
socket.shutdownOutput();
6.关闭相关套接字对象即可.
if(socket!=null){
socket.close();
socket=null;
}
if(serverSocket!=null){
serverSocket.close();
serverSocket=null;
}
(二)、基于TCP协议的客户端编程步骤:
1.实例化通讯套接字对象并指定服务器的IP地址和服务器正在监听的端口号
socket=new Socket(InetAddress.getLocalHost(),8000);
2.通过通讯套接字得到输入流和输出流对象完成读写功能
InputStream inputStream=socket.getInputStream();
OutputStream outputStream=socket.getOutputStream();
3.向服务器写出需要的数据
outputStream.write("活着的长久的都是聪明人和坏人,而那些死得早的都是那些蠢人和好人".getBytes());
socket.shutdownOutput();//告诉服务器端我已经将数据写完了。(向服务器写出一个结束标记)
4、读取服务器回送回来的数据
byte[] buffer=new byte[1024];
int len=0;
StringBuilder stringBuilder=new StringBuilder();
//如果没有收到读取结束的标识符,则这个方法一直读取数据,如果读取不到则被阻塞.
while((len=inputStream.read(buffer))!=-1){
stringBuilder.append(new String(buffer,0,len));
}
//关闭套接字
if(socket!=null){
socket.close();
socket=null;
}
三、UDP
(一)UDP(User Datagram Protocol): 用户数据报协议
特点:面向无连接的不可靠的协议,每次传输数据的大小不能超过64K,不保证发送过去的数据接收方一定能够收到,如果收不到,就拉倒。因此不安全。
(二)、用户数据报协议的接收方的编程步骤:
A:实例化数据报套接字对象并指定监听的端口号
DatagramSocket datagramSocket=new DatagramSocket(8000);
B:实例化数据包对象用来接收发送方发送过来的数据
byte[] buffer=new byte[1024];
int len=buffer.length;
DatagramPacket datagramPacket=new DatagramPacket(buffer, len);
C:调用数据报套接字的receive(dp)方法等待接收发送方法发送过来的数据。
datagramSocket.receive(datagramPacket);
D:通过数据报包对象得到发送方的IP地址和端口号
String sendIP=datagramPacket.getAddress().getHostAddress();
int sendPort=datagramPacket.getPort();
E:解析数据报包得到发送过来的数据
byte[] data=datagramPacket.getData();//得到数据报包中数据对应的字节数组
len=datagramPacket.getLength();//得到发送过来数据的实际长度
String content=new String(data,0,len);//解码得到实际数据内容
(三)、基于UDP编程的发送方的编程步骤:
1.实例化数据报套接字对象
DatagramSocket datagramSocket=new DatagramSocket();
2.实例化数据报包对象并指定需要发送的数据,数据的长度,目标主机的IP地址和端口号
byte[] data="我是发送方法发送过来的数据".getBytes();
DatagramPacket datagramPacket=new DatagramPacket(
data, //要发送的数据
data.length, //要发送数据的长度
InetAddress.getLocalHost(), //发送数据的目标主机的IP地址对象
8000//发数据目标主机正在监听的端口号
);
3.调用数据报套接字的send(dp)发送数据到接收方
datagramSocket.send(datagramPacket);
四、HttpURLConnection
(一)、采用Get提交方式访问服务器并得到服务器返回的数据
String path=“https://www.baidu.com/img/bd_logo1.png”;
1.实例化URL对象并指定网址
URL url=new URL(path);
2.调用URL对象的openConnection() 并转化成子类HttpURLConnection类型的对象
URLConnection urlConnection =url.openConnection();
HttpURLConnection httpURLConnection=(HttpURLConnection) urlConnection;
3.设置连接参数
httpURLConnection.setConnectTimeout(3000);//设置连接超时时间,单位是毫秒
httpURLConnection.setRequestMethod("GET");//设置请求方式为GET,必须全部大写
4.将本次请求提交到服务器端并得到服务器端的响应
int responseCode=httpURLConnection.getResponseCode();
if(responseCode==200){//如果响应码等于200,表示本次请求并得到服务器端响应成功
InputStream inputStream=httpURLConnection.getInputStream();
//3.实例化本地生成的文件
int index=path.lastIndexOf(".");
//得到目标文件的扩展名
String extName=path.substring(index);//.png
File destFile=new File(System.currentTimeMillis()+extName);
//将目标文件包装成输出流对象
OutputStream outputStream=new FileOutputStream(destFile);
byte[] buffer=new byte[1024];
int len=0;
while((len=inputStream.read(buffer))!=-1){
outputStream.write(buffer,0,len);
}
System.out.println("文件下载完成!");
}else{
System.out.println("本次网络请求失败!");
}
(二)、采用Post提交方式访问服务器并得到服务器返回的数据
1.实例化URL对象并关联上网址
URL url=new URL(path);
2.打开连接返回URLConnection类型的对象
HttpURLConnection httpURLConnection=(HttpURLConnection) url.openConnection();
3.设置连接参数
httpURLConnection.setConnectTimeout(3000);//设置连接超时时间,单位是毫秒
httpURLConnection.setRequestMethod("POST");//设置提交方式为POST提交
4.设置允许向服务器写出数据的功能:true:允许使用HttpURLConnection向服务器端写数据,false不允许,默认值为false
httpURLConnection.setDoOutput(true);
5.准备提交到服务器端的参数
String param="userName=小丽&pwd=123";
6.得到输出流对象
OutputStream outputStream=httpURLConnection.getOutputStream();
7.将需要提交到服务器端的参数转化成字节数组写向服务器端
outputStream.write(param.getBytes());
8.将请求提交到服务器端并得到服务器返回的数据
int responseCode=httpURLConnection.getResponseCode();
9.得到输入流读取服务器端返回的数据
if(responseCode==200){
InputStream inputStream=httpURLConnection.getInputStream();
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=0;
while((len=inputStream.read(buffer))!=-1){
byteArrayOutputStream.write(buffer,0,len);
}
String content=byteArrayOutputStream.toString();
}
(二)、采用get提交方式访问服务器并得到服务器返回的数据
String path=“http://localhost:8080/HelloDemo01/servletLifeCycleDemo01?userName=小丽&pwd=123”;
1.实例化URL对象并关联上网址
URL url=new URL(path);
2.打开连接返回URLConnection类型的对象
HttpURLConnection httpURLConnection=(HttpURLConnection) url.openConnection();
3.设置连接参数
httpURLConnection.setConnectTimeout(3000);//设置连接超时时间,单位是毫秒
httpURLConnection.setRequestMethod("GET");//设置提交方式为GET提交,此处可以不设,因为默认值就是GET
4.将请求提交到服务器端并得到服务器返回的数据
int responseCode=httpURLConnection.getResponseCode();
5.得到输入流读取服务器端返回的数据
if(responseCode==200){
InputStream inputStream=httpURLConnection.getInputStream();
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=0;
while((len=inputStream.read(buffer))!=-1){
byteArrayOutputStream.write(buffer,0,len);
}
String content=byteArrayOutputStream.toString();
}
五、多线程下载
public class MultipleThreadDownLoadDemo01 {
public static void main(String[] args) {
String src="src"+File.separator+"wife.mp3";
String dest="src"+File.separator+"wife_dest.mp3";
//打算启动几个线程下载
int threadNum=3;
for(int i=0;i<threadNum;i++){
new DownLoadFile(src,dest,threadNum,i,"线程"+(i+1)+"号").start();
}
}
/**
* 采用多线程完成数据的下载
* @author dell
*
*/
static class DownLoadFile extends Thread{
private RandomAccessFile randomAccessFile_src;
private RandomAccessFile randomAccessFile_dest;
/**
* 存放每个线程需要下载的文件的大小
*/
private long size;
/**
* 完成数据下载操作
* @param src 需要下载的源文件
* @param dest 下载完成后生成的目标文件
* @param threadNum 线程数
* @param currentThreadId 当前线程编号
* @param threadName 当前线程的名称
*/
public DownLoadFile(String src, String dest, int threadNum, int currentThreadId,String threadName) {
try {
//实例化需要下载的源文件
File srcFile=new File(src);
//实例化需要下载的目标文件
File destFile=new File(dest);
//得到需要下载源文件的总大小
long fileTotalSize=srcFile.length();
//计算每一个线程需要下载文件的大小
long temp=fileTotalSize/threadNum;//计算临时数据
//计算出来最终的每个线程需要下载的文件的大小
size=fileTotalSize%threadNum==0?temp:temp+1;
long fileStart=size*currentThreadId;
//实例化随机访问文件并指定源文件的路径和操作模式
this.randomAccessFile_src=new RandomAccessFile(srcFile,"r");
//实例化随机访问文件并指定目标文件的路径和操作模式
this.randomAccessFile_dest=new RandomAccessFile(destFile,"rw");
this.randomAccessFile_src.seek(fileStart);
this.randomAccessFile_dest.seek(fileStart);
System.out.println(this.getName()+"从"+fileStart+"位置开始下载");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
//定义累加器,目的是累计每个线程当前下载的大小,如果sum==size则说明当前线程完成下载任务
int sum=0;
byte[] buffer=new byte[1024];
int len=0;
try {
while((len=randomAccessFile_src.read(buffer))!=-1 && sum<size){
sum+=len;
this.randomAccessFile_dest.write(buffer,0,len);
}
System.out.println(Thread.currentThread().getName()+"完成下载");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(randomAccessFile_src!=null){
randomAccessFile_src.close();
randomAccessFile_src=null;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(randomAccessFile_dest!=null){
randomAccessFile_dest.close();
randomAccessFile_dest=null;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}