网络编程
概述:
通讯三要素:
1、IP地址:找到对方,通过IP地址
2、逻辑端口:数据要发送到对方指定的应用程序上,为了标识这些应用程式,所以给这些网络应用程序都用数字进行标识。这个标识就叫做端口。
3、协议:定义通讯规则。这个通讯规则成为协议。
国际组织定义了通用协议:TCP/IP
端口范围:0~~65535,0~1024被系统保留
常见端口:web:80 ; Tomcat:8080 ; MySQL:3306
常见协议:TCP 、UDP
本地主机IP地址:127.0.0.1,名称:localhost。两者对应,跟网址和域名的关系。
————————————————————————————
InetAddress:用于描述IP的类
方法:
String getHostAddress();:返回对象IP地址的字符串形式
String getHostName(); :返回对象的主机名
static InetAddress getLocalHost():获取本地主机对象
static InetAddress getByName("IP地址"):获取IP地址或者域名获取主机对象。
static InetAddress[] getAllByAddress("域名"):通过主机名或者域名获取不同IP地址的主机对象数组。
注:如果IP地址和对应的主机名这个映射关系没有在网络上,其他主机通过IP地址去搜索到了,但是会有没解释成功的情况,getHostName()获取的还是IP的地址;getHostName();会有一个解释过程。
当输入域名用getByName方法获取主机对象时,IP地址并不是唯一的。因为网络上的服务器可能有多台,对应不用的IP地址,这时就要用:getAllByAddress方法。大部分用getAllByAddress方法为主,因为getHostName方法需要解释。
public static void main(String[] args) throws Exception
{
InetAddress i = InetAddress.getLocalHost();
System.out.println("address"+i.getHostAddress());
System.out.println("name:"+i.getHostName());
InetAddress ia = InetAddress.getByName("www.163.com");
System.out.println("address:"+ia.getHostAddress());
System.out.println("name:"+ia.getHostName());
InetAddress[] ias = InetAddress.getAllByName("www.baidu.com");
System.out.println("Address:"+ias[0].getHostAddress());
System.out.println("Name:"+ias[0].getHostName());
System.out.println("Address:"+ias[1].getHostAddress());
System.out.println("Name:"+ias[1].getHostName());
}
——————————————————
Socket
socket是为网络服务提供的一种机制。
通信两端都有Socket,网络通讯其实就是Socket间的通讯,通过IO传输
IP地址最后一段255是广播地址,会发送到当前网段的所有机器上(1-254)
UDP传输:
特点:
1、面向无连接;
2、发送时需要把数据封装成一个个数据报,每个数据包不能超过64K;
3、速度快,容易丢失数据报;
4、因为特点1,所以是不可靠的协议;
面向无连接:网络通讯有接收端和发送端,发送端发送数据包到接收端,接收端在不在网络上都没关系,在就接收到,不在数据包就丢失。
应用:聊天工具如:qq、icq之类的就是UDP,视频通讯之类的也是UDP
UDP对象:DatagramSocket 用于发送和接收
UDP传输数据包对象:DatagramPacket;用于接收和封装数据。凡是构造函数参数要IP地址对象和端口的都是用于构造发送数据包。空参数是用于接收数据。
UDP发送端思路:通过UDP传输方式,将一段数据发送出去。
1、建立UDPSocket服务(DatagramSocket对象)
2、提供数据,并将数据封装到数据包中(DatagramPacket对象)
3、通过Socket服务的发送功能,将数据包发送出去。(ds.send(dp))
{
DatagramSocket ds = new DatagramSocket();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String len = null;
do
{
len =br.readLine();
byte[] but =len.getBytes();
DatagramPacket dp = new DatagramPacket(but,but.length,InetAddress.getByName("192.168.2.255"),11111);
ds.send(dp);
}
while(!len.equals("over"));
ds.close();
br.close();
}
UDP发送端思路:定义一个应用程序,用于接收UDP协议传输的数据并处理
1、定义UDPSocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据传输过来后是该应用程序可以处理的。
2、定义一个空的数据包,用于存储接收到的字节数据。因为数据包对象中有更多的功能可以崎岖字节数据中的同数据信息。
3通过Socket服务的receive方法接收到的数据存入已定义好的数据包中。
4、通过数据包对象的特有功能,将这些不同的数据取出。
5、关闭资源。
注意:不手动定义端口的话,虚拟机会自动添加一个端口,但是就会和发送端定义的端口对应不上,就接收不到数据。另外,DatagramPacket中的getPort()是获取发送端的自身的端口,而不是发送端的目的端口。
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(11111);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
String str = null;
while(true)
{
ds.receive(dp);
str = new String(buf,0,dp.getLength());
String ip = dp.getAddress().getHostAddress();
System.out.println(ip+"::"+str);
}
}
TCP传输:
特点:
1、面向连接,用3次握手判断
2、没有数据包大小限制
3、速度相对稍慢。
4、是可靠的协议。
三次握手:就是发送端发送数据到接收端,接收端收到后反馈数据给发送端通知接收到。发送端接收到反馈数据后,再反馈数据给接收端通知收到了。
TCP对象:Socket客户端和ServerSocket服务端
客户端在建立对象时,就去连接指定主机。因为TCP是面向连接的,所以在Socket服务建立时,就要有服务端存在,才能连接成功。形成通道后,在该通路进行数据的传输。
建立对象后是通过Socket流通讯:
OutputStream getOutputStream():输出流,从调用对象往外流。
InputStream getInputStream():输入流,接收外面往调用对象。
客户端:
public static void main(String[] args) throws IOException
{
//创建客户端的socket服务。指定目的主机和端口
Socket sock = new Socket("192.168.2.100",11011);
//为了发送数据,应该获取socket流中的输出流。
OutputStream os = sock.getOutputStream();
//发送数据
os.write("dfsgdfgsdfgsdfgsdfgsd".getBytes());
sock.close();
}
服务端通过获取客户端的Socket对象的影像,来进行不同客户端的管理。
Socket accept():获取连接到服务端的客户端的Socket对象。
服务端:
1、建立服务端的Socket服务:ServerSocket(),并监听一个端口。
2、获取连接过来的客户端对象。通过ServerSocket的accept方法;没有连接请求就会等待,左移这个方法是阻塞式。
3、客户端如果发送数据过来,那么服务端要使用对应的客户端对象,并获取到该对象的读取流来读取发送过来的数据。
4、关闭服务端(可选,因为服务端的存在并不为了单一客户端。所以服务端一般长期开着,灯虎客户端的接入。所以这里可以通过关闭服务端上的客户端对象来完成断开连接。)
public static void main(String[] args) throws IOException
{
//建立服务端socket服务。并监听一个端口。
ServerSocket ss = new ServerSocket(11011);
while(true)
{
//通过accept方法获取连接过来的客户端对象。
Socket sock = ss.accept();
//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
InputStream is = sock.getInputStream();
String ip = sock.getInetAddress().getHostAddress();
byte[] buf = new byte[1024];
int len = is.read(buf);
System.out.println(ip+"::"+new String(buf,0,len));
//服务端关闭客户度的连接
sock.close();
}
}
注意:当客户端和服务端交流,都用Buffered装饰和转换流进行键盘的读取和反馈时,服务端用readLine方法读取客户端发送数据,客户端在发送数据时,除了要write()以外还要花上newLine()作为结束标记,不然服务端的readLine()会一直等待,同理,客户端读取服务端readLine()方法也是一样。还有write()和newLine()后要记得flush()刷新。
/*
演示tcp的传输的客户端和服务端的互访。
需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
*/
/*
客户端:
1,建立socket服务。指定要连接主机和端口。
2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
4,关闭客户端资源。
*/
import java.io.*;
import java.net.*;
class myServer2
{
public static void main(String[] args) throws Exception
{
//建立服务端
ServerSocket server = new ServerSocket(10022);
while(true)
{
//获取客户端对象
Socket s = server.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...连接服务器!");
//客户端对象输出流和读取流
//BufferedWriter bfos = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader bfis = new BufferedReader(new InputStreamReader(s.getInputStream()));
//简化代码不用BufferedWriter和转换流,用PrintWriter;
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
//循环获取客户端信息和进行反馈
while(true)
{
String line = bfis.readLine();//当客户端关闭,这里就会返回-1
if("over".equals(line))
break;
System.out.println(ip+"::"+line);
pw.println(line.toUpperCase());
/*
bfos.write(line.toUpperCase());
//跟客户端一样,要加上,不然客户端那里也是等待
bfos.newLine();
bfos.flush();
*/
}
System.out.println(ip+"...以结束连接!");
s.close();
}
}
}
class myTcpDemo2
{
public static void main(String[] args) throws Exception
{
//客户端连接
Socket sock = new Socket("192.168.2.100",10022);
//获取键盘录入
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
//客户端输出流和读取流
//BufferedWriter bfos = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
BufferedReader bfis = new BufferedReader(new InputStreamReader(sock.getInputStream()));
//简化代码不用BufferedWriter和转换流,用PrintWriter;
PrintWriter pw = new PrintWriter(sock.getOutputStream(),true);
String line = null;
while((line=bfr.readLine())!=null)
{
if("over".equals(line))
{
pw.println(line);
/*
bfos.write(line);
bfos.flush();*/
break;
}
pw.println(line);
/*
bfos.write(line);
//这里要加上newLine方法,不然服务端那里的readLine方法没有读取到换行,就会一直等待
bfos.newLine();
bfos.flush();
*/
String str = bfis.readLine();
System.out.println("Server::"+str);
}
bfr.close();
sock.close();
}
}
————————————————————————————————
URL
URL代表同意资源定位符,URI也是,不过比URL的范围大。
构造函数:以String形式传入整个网址,或者也可以根据不同的部分分别传入协议、域名、端口、文件等
常见方法
String geProtocol():获取协议,如http、ftp
String getHost():获取主机的IP地址或者域名
int getPort():获取端口,未设置返回默认-1,即80端口
String getPath():获取路径,但网址不带参数时两者一样,网址带上参数后,getFile就跟上参数,getPath就不跟
String getFile():获取文件,但网址不带参数时两者一样,网址带上参数后,getFile就跟上参数,getPath就不跟
String getQuery():获取路径后面的参数,没有时返回null
URLConnection openConnection():获取URL的连接对象URLConnection,一调用该方法就已经连接上了服务端,请求头也已经发送,之后只要获取读取流读取服务端发送过来的数据即可。
InputStream openStream():就是openConnection().getInputStream()的缩写,先连接,再获取读取流
public static void main(String[] args) throws Exception
{
URL url = new URL("http://192.168.2.100:8080/myweb/demo.html");
URLConnection conn = url.openConnection();
System.out.println(conn);
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
}
DNS服务器就是域名解释服务器,记录了域名和IP地址的映射关系
IE访问网络:先去本机的HOSTS文件查找网址的IP地址;没有时再到DNS服务器上查找网址的IP地址,最后才访问网站