黑马程序员_java之网络编程
网络编程
网络通讯三要素:IP地址、端口号、传输协议
特殊IP地址:127.0.0.1本地回环地址,对应的主机名为 localhost,可用来测试网卡ping 127.0.0.1;192.168常用保留地址段,IPV4 、IPV6(可以数字和字母)
端口号:标示进程的逻辑地址,有效端口为0-65535,其中0-1024为系统使用或保留端口;常见端口:
Web端口80 Tomact端口8080 MySql 3306
协议:常见协议TCP/IP、UDP, 例:特有机构有专门的协议
网络模型:OSI参考模型,TCP/IP参考模型
OSI参考模型:应用层(数据+应用层特征)、表示层、会话层、传输层(+TCP/UDP信息)、网络层(+IP信息)、数据链路层(+传输方式、底层协议)、物理层(物理层设备如网线、光纤、无线(红外))
TCP/IP参考模型:应用层、传输层、网际层、主机至网络层
TCP传输控制协议、UDP用户数据报协议、FTP/HTTP 应用层协议
Web开发在应用层、网络编程在传输层、网际层
两台电脑通讯:先不断数据封包、再不断数据拆包。
获取IP信息:通过java.net包中的InetAddress
例子:InetAddress ia=InetAddress.getLocalHost();//获取主机名,本地IP信息
InetAddress ia2=InetAddress.getByName (“”);//获取任一台主机信息
//若IP地址和主机名映射关系没在网络上。能找到IP地址,解析不成功,名字还是IP地址
Ia.getHostAddress();//获取IP地址
Ia.getHostName();//获取主机名
TCP和UDP区别:
UDP:将数据及源和目的封装成数据包中,不需建立连接
每个数据包大小限制在64K内
因无连接,是不可靠协议,易丢包
因不需建立连接,速度快
常见应用:聊天、网络视频、桌面共享
TCP:建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接,可靠
面向连接、效率稍低
Socket:为网络服务提供的一种机制
通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket之间通过IO传输
Socket相当于码头中的港口,每个应用程序都有类似的插座
UDP发送接收数据:
DatagramSocket 发送接收数据包套接字 DatagramPacket无连接包投递服务
发送端发送数据步骤:1、建立发送端服务
2、提供数据包并打包
3、通过socket服务发送
4、关闭资源
接收端接收数据步骤:1、建立接收端服务,通常监听一端口
2、定义数据包存储接收数据
3、通过socket服务接收数据存入定义的数据包中
4、通过数据包对象取出数据
5、关闭资源
/需求:通过udp传输方式,将一段文字数据发出去
class UdpSend {
public static void main(String[] args)throws Exception {
DatagramSocket ds=new DatagramSocket();
byte [] buf="udp ge men lai le".getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("169.254.112.87"),10000);
ds.send(dp);
ds.close();
}
}
//定义一个应用程序。用于接收udp协议传输的数据并处理
class UdpRece {
public static void main(String[] args)throws Exception {
DatagramSocket ds=new DatagramSocket(10001);
byte [] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);//阻塞式方法
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
ds.close();
}
}
Udp键盘录入数据:接收端用while(true),不会死循环,有阻塞式方法;去掉关闭资源语句
编写一个聊天程序
TCP发送接收数据:
客户端Socket 服务端ServerSocket
客户端发送数据步骤:1、建立Socket服务,并指定要连接的主机名和端口
2、获取Socket流中的输出流
3、关闭资源
接收端接收数据步骤:1、建立Socket服务,通过ServerSocket,通常监听一端口
2、获取连接过来的Socket对象,通过accept方法(阻塞式)
3、获取socket对象的读取流
4、关闭资源(关闭客服端;而关闭服务端可选)
//给服务端发送一个文本数据
class TcpClinet {
public static void main(String[] args) throws Exception {
Socket s=new Socket("169.254.112.87",10005);
OutputStream out=s.getOutputStream();
out.write("tcp ge men lai le".getBytes());
s.close();
}
}
//建立断点接收数据,并打印在控制台
class TcpServer{
public static void main(String[] args)throws Exception {
ServerSocket ss=new ServerSocket(10005);
Socket s=ss.accept();//阻塞式方法
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
InputStream in=s.getInputStream();//源是网络流
byte [] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
ss.close();//可选
}
}
演示:Tcp传输的客户端和服务端互访
客户端发完后就会等因为read是阻塞式方法
TCP练习:服务端客户端容易两边挂起,如TCP复制文件,服务端反馈上传成功,因为服务端客户端都用到readline方法,而此方法是阻塞式方法,
如果不加结束标记的话,两端都会莫名的等待。有两种解决方式一种是加时间戳另外一种是Socket对象的shutdownOutput方法。
import java.io.*;
import java.net.*;
class TextClinet {
public static void main(String[] args) throws Exception {
Socket s=new Socket("169.254.112.87",10008);
BufferedReader bufr=
new BufferedReader(new FileReader("IPDemo.java"));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
//时间戳
/*DataOutputStream dos=new DataOutputStream(s.getOutputStream());
long time=System.currentTimeMillis();
dos.writeLong(time);*/
String line=null;
while((line=bufr.readLine())!=null){
out.println(line);
}
//dos.writeLong(time);
//关闭客户端输出流,相当于给流结束标记-1
s.shutdownOutput();
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
String str=bufIn.readLine();
System.out.println("server:"+str);
bufr.close();
s.close();
}
}
class TextServer{
public static void main(String[] args) throws Exception {
ServerSocket ss=new ServerSocket(10008);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
//时间戳
/*DataInputStream dis=new DataInputStream(s.getInputStream());
long l=dis.readLong();*/
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
//文件名字写死了
PrintWriter out=new PrintWriter(new FileWriter("server.txt"),true);
String line=null;
while((line=bufIn.readLine())!=null){
//判断时间戳
out.println(line); //读到了,但是没结束标记,就会等
}
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
pw.println("上传成功");
out.close();
s.close();
ss.close();
}
}
URL对象(统一资源定位符):URI范围比URI大
String getHost() 返回此 URI 的主机组成部分。
String getPath() 返回此 URI 的已解码的路径组成部分。
int getPort() 返回此 URI 的端口号。
String getQuery() 返回此 URI 的已解码的查询组成部分。
String getProtocol() 获取协议名称
String getFile() 获取文件名
注:int port=url.getPort();if(port==-1;port=80;
例URL url=new URL(“”);
URLConnection conn=url.openConnection();//内部封装了Socket对象
InputStream in=conn.getInputStream();
Byte [] buf =new byte[1024];
Int len=0;
While((len=in.read(buf))!=-1){
Sop(new string(buf,0,len));
}
注:Socket()构造函数void connect(SocketAddress endpoint) 将此套接字连接到服务器。SocketAddress抽象类有子类InetSocketAddress封装的是IP 地址 + 端口号
ServerSocket(int port, int backlog),backlog队列的最大长度,能连接到服务器的最多客服端个数