一、概述
(一)网络传输过程
1.找到对方IP
2.数据要发送到对方指定的应用程序上。为了标示这些应用程序,给这些APP都用数字进行标识。即是端口(逻辑端口)
3.定义通讯协议 TCP/IP协议 192.168.1.254-局域网保留地址
(二)网络模型
OSI参考模型
TCP/IP参考模型
1.OSI参考模型OpenStyleInternet
数据封包:层层封装数据添加每个层次的特有信息
应用层
表示层
会话层
传输层 tcp
网络层 ip
数据链路层
物理层 网线 光纤无线网
2.TCP/IP参考模型
tcp/ip模型将上三层理解为应用层http/ftp
传输层 tcp udp
网际层 ip
将下二层理解为基本底层(主机至网络层)
传输给目标地址后:数据拆包,到应用层后数据根据端口发送到相应的程序
写程序:
网络编程“网际层和传输层”
Javaweb开发在应用层
(三)网络传输基本三要素:IP 端口协议
1. IP
本地回环地址:127.0.0.1 主机名:localhost
有专门描述IP对象的类
import java.net.*;
Class InetAddress
|--Inet4Address
|--Inet6Address
无构造函数,有非静态方法和静态方法,说明有静态方法获取本类对象
获取IP对象的方法以getHostAddress()为主
2.端口
用于表示进程的逻辑地址,不同进程标识不同
有效端口0-65535 0-1024为系统使用或保留端口
因为只有数字标识,所以不需要对象
3.协议
UDP:无连接,限制大小,不可靠,速度快
a.面向无连接(发数据之前不需要建立连接(邮局寄送包裹))
b.将数据源和目的地一同封包
c.每个数据包的大小被限制在64k以内
d.因为是无连接。是不可靠协议
e.不需要建立连接,速度快
聊天就是UDP
TCP:必连接,大数据,可靠,效率稍低
a.必须连接,形成传输数据的通道。三次握手,s-在吗? r-在,你在?s-在,开始吧
b.连接中进行大数据量传输
c.通过三次握手完成连接,可靠
d.必须建立连接,效率稍低
下载 是tcp
电话是tcp,步话机是udp
二、IP对象
1获取指定IP对象的方法
1)getByName()
a.url
b.ip
2)getAllByName()
3)getByAddress()
4)getLocalHost()
2获取IP对象地址
3获取IP对象的名称
InetAddressi1a=InetAddress.getByName(“www.baidu.com”);
InetAddress i1b=InetAddress.getByName(“192.168.1.100”);
InetAddress[] i2=InetAddress.getAllByName(“www.baidu.com”);
InetAddress i3=InetAddress.getByAddress(newbyte[]{(byte)192,(byte)168,1,101});
InetAddress i4=InetAddress.geLocalHost();
i4.getHostName();
i4.getHostAddress();
=================
150527 add:
可以对InetAddress对象调用getAddress()方法获取其地址值的byte[4]数组。用处:进行ip地址的大小比较。for循环4次,如果当前段数值相同则continue;byte超过127则表示为负数,所以比较两个段数值的大小,必须分情况讨论。
getByName获取ip对象时需要处理异常:UnknownHostException
三、Socket套接字对象
Socket是为网络服务提供的一种机制
通信的两端都有Socket。
网络通信的实质就是Socket之间的通信
数据在两个Socket之间通过IO传输
Socket是传输的通路,先有码头,才有船运输货物
不同传输协议有不同的Socket
(一)UDP
DatagramSocket此类标识用来发送和接收UDP协议数据报包的套接字,既可以发送也可以接收
==========
150527 add:
DatagramSocket在新建对象时可以指定使用的端口号,这样就不容易冲突 ds=new DatagramSocket(10086);
新建DatagramSocket需要处理 SocketException
DatagramPacket表示数据报包
数据报包实现无连接包投递服务
DatagramPacket(byte[] buf,intlength,InetAddress addr,int port)//发送
带地址的方法都是用于发送数据
DatagramPacket(byte[] buf,int length)//接收
==========
150527 add:
这里传入数据报包的参数是缓冲区字节数组以及数组长度!length应当传入的是buf.length而不是cntBuf。
send(DatagramPacket p)//从此套接字发送数据报包
receive(DatagramPacket p)//从此套接字接收数据报包
UDP发送
通过UDP传输方式,将一段文字数据发送出去
思路:
1建立UDP Socket服务
2提供数据,并将数据封装到数据包中
3通过Socket服务的发送功能,将数据包发送出去,
4关闭资源(因为数据包的传输至少要通过网卡)
DatagramSocket ds=new DatagramSocket();
byte[] buf=”hello”.getBytes();
DatagramPacket dp= new DatagramPacket(buf,buf.length,InetAddress.getByName(“192.168.1.100”),10000);
ds.send(dp);
ds.close();
UDP接收
DatagramPacket获取数据报包数据的方法:
ip对象InetAddress getAddress()
端口int getPort()
字节数据数组byte[] getData()
字节数据长度int getLength
DatagramSocket ds=new DatagramSocket();
byte[] buf= byte[1024];
DatagramPacket dp=newDatagramPacket(buf,buf.length);
ds.receive(dp);
String ip=dp.getAddress().getHostAddress();
int port=dp.getPort();
String info=new String(dp.getData(),0,dp.getLength());
ds,close();
import java.net.*;
import java.io.*;
/*发送键盘录入的数据到目标地址
1建立输入流 bin
-关闭bin
2.建立套接字
-关闭套接字
3.处理输入的数据
4.建立数据报包
5.使用套接字发送服务
*/
class UDPSender implements Runnable{
public void run() {
byte[] buf = null;
String tmp=null;
BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
DatagramSocket ds = null;
DatagramPacket dp = null;
try {
ds = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
try {
while(!"over".equals(tmp=bin.readLine())){
buf=tmp.getBytes();
try {
dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
try {
bin.close();
} catch (IOException e) {
e.printStackTrace();
}
if(null!=ds){
ds.close();
}
}
}
class UDPReceiver implements Runnable{
public void run() {
DatagramSocket ds=null;
DatagramPacket dp=null;
byte[] buf=new byte[1024];
try {
ds=new DatagramSocket(10086);
} catch (SocketException e) {
e.printStackTrace();
}
while(true){
dp=new DatagramPacket(buf,buf.length);
try {
ds.receive(dp);
} catch (IOException e) {
e.printStackTrace();
}
String ip= dp.getAddress().getHostAddress();
int port=dp.getPort();
String info=new String(dp.getData(),0,dp.getLength());
System.out.println("ip: "+ip+":"+port+" - "+info);
}
}
}
class host1{
public static void main(String[] args){
new Thread(new UDPSender()).start();
new Thread(new UDPReceiver()).start();
}
}
class test2{
public static void main(String[] args){
new Thread(new UDPSender()).start();
new Thread(new UDPReceiver()).start();
}
}
(二)TCP
UDP分发送端和接收端
TCP分客户端Socket和服务器端ServerSocket
1.建立Socket和ServerSocket
2.建立连接后,通过Socket中的IO流进行数据的传输
3.关闭Socket
Socket
1.ctor
Socket(InetAddress address,int port)
Socket()//空参数的ctor可以在创建对象后使用connect方法进行连接
因为TCP面向连接,所以建立时就须要有服务器端存在,并连接成功。
形成通路后再向该通路进行数据传输
2.接收
1)创建客户端对象:
Socket()//创建空参数的客户端对象,一般用于服务端接收数据
Socket(String host,int port)//指定要接收的IP地址和端口号
2)创建服务端对象:ServerSocket(int port)//指定接收的客户端的端口
3)Socket accept()//监听并接受到此套接字的连接
4)InputStream getInputStream()//返回此套接字的输入流,Socket对象调用
5)OutputStream getOutputStream()//返回套接字的输出流,Socket对象调用
3.基本思路
客户端:
1)客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。
2)连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream(),getOutputStream()获取即可。
3)与服务端通讯结束后,关闭Socket。
服务端:
1)服务端需要明确它要处理的数据是从哪个端口进入的。
2)当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。
3)当该客户端访问结束,关闭该客户端。
4.步骤
客户端:
1)创建Socket服务,并指定要连接的主机端口。通路一建立,就会产生Socket流(包括输入流和输出流),通过方法获取
2)为了发送数据,应获取Socket中的输出流,如果要接收服务端的反馈信息,还需要获取Socket的输入流
3)通过输出流的write()方法将要发送的数据写入到流中
4)关闭Socket流资源
服务端:
1)建立服务端的Socket服务,并监听一个端口。
2)获取连接过来的客户对象,通过ServerSocket的accept()方法,此方法是阻塞式的,如果服务端没有连接到就会一直等待
3)客户端如果发过来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过来的数据,并输出到指定目的地。
4)关闭客户端的套接字资源。
import java.net.*;
import java.io.*;
class TCPSender implements Runnable {
public void run() {
Socket s = null;
try {
s = new Socket(InetAddress.getByName("192.168.1.100"), 10000);
} catch (UnknownHostException e2) {
e2.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
OutputStream out = null;
try {
out = s.getOutputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
out.write("hello!".getBytes());
} catch (IOException e1) {
e1.printStackTrace();
}
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class TCPReceiver implements Runnable {
public void run() {
ServerSocket ss = null;
try {
ss = new ServerSocket(10000);
} catch (IOException e) {
e.printStackTrace();
}
Socket s = null;
try {
s = ss.accept();
} catch (IOException e1) {
e1.printStackTrace();
}
InputStream in = null;
try {
in = s.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
byte[] buf = new byte[1024];
int cnt = 0;
try {
cnt = in.read(buf);
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println(new String(buf, 0, cnt));
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器端并发处理客户端的连接:
ServerSocket sServer=newServerSocket(port);
while(true)
{
newThread(new Session(sServer.accept())).start();
}
客户端上传图片到服务器端
1.客户端:
1创建tcp的套接字
2获取输出流
3获取文件输入流
4将图片传输到服务器端
服务器端:
1.创建服务器端tcp套接字
2.循环accept获取新的客户端套接字
3.获取客户端的输入流
4.获取文件输出流
5.保存图片并添加时间戳
import java.net.*;
import java.util.Date;
import java.io.*;
import java.text.*;
class TCPSender implements Runnable {
private String strIP;
private int port;
private File file;
public TCPSender(String strIP,int port,File file) {
super();
this.port = port;
this.strIP = strIP;
this.file=file;
}
public void run() {
Socket s=null;
FileInputStream fin=null;
byte[]buf=new byte[1024*20];
int cntBuf=0;
try {
fin=new FileInputStream(file);
s=new Socket(strIP,port);
OutputStream sout=s.getOutputStream();
InputStream sin=s.getInputStream();
byte[] filename=file.getName().getBytes();
sout.write(filename);
cntBuf=sin.read(buf);
if("accept_name".equals(new String(buf,0,cntBuf))){
System.out.println("filename accepted,begin sending data");
while(-1!=(cntBuf=fin.read(buf))){
sout.write(buf,0,cntBuf);
}
}else{
System.out.println("filename not accepted,closing connection");
}
s.shutdownOutput();
cntBuf=sin.read(buf);
System.out.println(new String(buf,0,cntBuf));
}
catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("cannot find the file");
}
catch (UnknownHostException e) {
e.printStackTrace();
throw new RuntimeException("cannot find the host");
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(null!=fin){
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null!=s){
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class Session implements Runnable {
private Socket sClient;
private String path="G:\\Codes\\Language\\JAVA\\Project\\eclipse\\workspace\\test\\temp";
public Session(Socket sClient) {
super();
this.sClient = sClient;
}
public void run() {
byte[] buf=new byte[1024*20];
int cntBuf=0;
FileOutputStream fout=null;
InputStream sin=null;
OutputStream sout=null;
try {
sin=sClient.getInputStream();
sout=sClient.getOutputStream();
cntBuf=sin.read(buf);
String fileName=new String(buf,0,cntBuf);
System.out.println(fileName);
if(checkName(fileName)){
fout=new FileOutputStream(new File(path,getTimeNow()+fileName));
sout.write("accept_name".getBytes());
while(-1!=(cntBuf=sin.read(buf))){
fout.write(buf,0,cntBuf);
}
sout.write("upload completely".getBytes());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
sClient.close();
} catch (IOException e) {
e.printStackTrace();
}
if(null!=fout){
try {
fout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String getTimeNow() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd_hh-mm-ss-SSS");
return "["+sdf.format(new Date())+"]";
}
// 可以利用此方法检查上传文件名
private boolean checkName(String string) {
return true;
}
}
//TCPServer
class test2 {
private static int port=12345;
public static void main(String[] args){
ServerSocket sServer=null;
try {
sServer=new ServerSocket(port);
while(true)
{
new Thread(new Session(sServer.accept())).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally{
if(null!=sServer){
try {
sServer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class TCPClient{
public static void main(String[] args) {
new Thread(new TCPSender("192.168.1.100",12345,new File("F:\\WallPaper\\Wall102.jpg"))).start();
}
}
四、URL和URLConnection
(一)URL
方法:
1 URL(Stringprotocol,String host,int port,String file);//根据指定 protocol、host、port号和 file 创建 URL对象。
2 StringgetProtocol();//获取协议名称
3 StringgetHost();//获取主机名
4 intgetPort();//获取端口号
5 StringgetFile();//获取URL文件名
6 StringgetPath();//获取此URL的路径部分
7 StringgetQuery();//获取此URL的查询部,客户端传输的特定信息
一般输入网址,是不带端口号的,此时可进行获取,通过获取网址返回的port,若port为-1,则分配一个默认的80端口,可能的实现形式:
int port = getPort();
if(port == -1){port = 80;}
(二)URLConnection
获取URLConnection对象:
URLConnection openConnection();//返回URLConnection 对象,表示到 URL 所引用的远程对象的连接。
//URL url=…;
URLConnection uc=url.openConnection();
URLConnection可以获取连接可使用的IO流
InputStream getInputStream();//获取输入流
OutputStream getOutputStream();//获取输出流
try{
//封装地址对象
URL url =new URL(path);
URLConnection conn=url.openConnection();
//获取流,用于读取服务器返回数据
InputStream in=conn.getInputStream();
//读取数据
byte[] buf=new byte[1024*1024];
int len=in.read(buf);
//将数据显示在文本区中
System.out.println(new String(buf,0,len));
}catch (Exception e){
throw new RuntimeException("连接"+path+"网站失败");
}