------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
1. InetAddress
表示互联网协议 (IP) 地址
代码示例
public class NetDemo {
public static void main(String[] args) throws Exception {
//获取本地IP实例
InetAddress address=InetAddress.getLocalHost();
//输出本地IP地址以及主机名
System.out.println(address.getHostAddress()+":"+address.getHostName());
//获取指定主机的地址对象
InetAddress address2=InetAddress.getByName("192.168.1.18");
//打印指定主机的IP地址以及主机名
System.out.println(address2.getHostAddress()+":"+address2.getHostName());
InetAddress ip=InetAddress.getByName("www.baidu.com");
System.out.println(ip.getHostAddress()+":"+ip.getHostName());
}
}
2.UDP数据报文包协议
无连接,不可靠的协议
不需要建立连接,所以效率高
每个数据报大小限制在64K内
DatagramSocket:表示用来发送和接收数据报包的套接字
DatagramPacket:此类表示数据包
数据包分为发送数据包和接收数据包
凡是发送数据包,参数都是带着地址的
UDP是无连接不可靠的协议,所以在没有接收端的情况下,发送端可以发送数据,且不会抛错,只不过是数据发丢了
代码示例
(1) 发送数据到接收端并显示
/*
* 通过UDP协议发送一段文本数据
*
* 接收端
* 思路:
* 1.先建立UDP的Socket.它具备发送或者接收功能
* 2.将数据封装到数据包中。数据包对象:DatagramPacket
* 3.使用Socket对象的send方法将数据包发送出去
* 4.关闭资源
*/
public class UDPSender {
public static void main(String[] args) throws IOException {
System.out.println("UDP发送端运行");
// 1.建立Socket
DatagramSocket ds = new DatagramSocket();
// 2.将数据封装到数据包中
String text = "UDP,你好";
// 将数据转成字节数组
byte[] buff = text.getBytes();
// 将字节数组封装到数据包中
InetAddress address = InetAddress.getByName("ZFY");
DatagramPacket dp = new DatagramPacket(buff,buff.length,address,
10086);
// 3.使用Socket对象的send方法发出数据包
ds.send(dp);
// 4.关闭资源
ds.close();
System.out.println("发送结束");
}
}
/*
* UDP接收端,接收发送过来的数据,并显示在屏幕上
* 思路:
* 1.先有UDP Socket服务(接收端必须明确端口,否则无法接收数据)
* 2.接收数据
* 3.先定义数据包
* 4.通过数据包对象获取数据包内容:发送端IP、端口、数据
* 5.关闭资源
*/
public class UDPReceive {
public static void main(String[] args) throws Exception {
System.out.println("UDP接收端运行");
//1 创建Socket服务
DatagramSocket ds=new DatagramSocket(10086);
//2 3 接收数据,将数据存储到数据包
byte[] buff=new byte[1024];
DatagramPacket dp=new DatagramPacket(buff,buff.length);
ds.receive(dp);//阻塞
//4 获取数据包内容
String ipString=dp.getAddress().getHostAddress();
int port=dp.getPort();
String text=new String(dp.getData(),0,dp.getLength());
System.out.println("接收到来自"+ipString+":"+port+"的数据:"+text);
//5 关闭资源
ds.close();
System.out.println("UDP接收结束");
}
}
(2)键盘录入信息发到接收端,由接收端将数据发回到发送端进行显示
/*
* 发送端:从键盘录入数据发送到接收端,输入bye退出
*
*/
public class UDPSender {
public static void main(String[] args) throws Exception {
System.out.println("发送端启动");
System.out.println("等待输入信息...");
//创建Socket
DatagramSocket socket=new DatagramSocket(10001);
DatagramPacket dp=null;
//获取本机地址
InetAddress address=InetAddress.getByName("127.0.0.1");
//从键盘录入信息
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line=null;
byte[] buff=null;
while((line=br.readLine())!=null){
buff=line.getBytes();
//创建数据包
dp=new DatagramPacket(buff,buff.length,address,10010);
//发送数据
socket.send(dp);
if(("bye".equals(line))){
break;
}
//接收从服务端发来的信息
socket.receive(dp);
//打印来自服务端的信息
System.out.println("来自接收端的信息:"+new String(dp.getData(),0,dp.getLength()));
}
//关闭资源
br.close();
socket.close();
System.out.println("发送端关闭");
}
}
/*
* 接收端:接收信息并显示到控制台,返回数据给发送端,接收到bye退出
*/
public class UDPReceive {
public static void main(String[] args) throws Exception {
System.out.println("接收端启动");
//创建Socket
DatagramSocket socket=new DatagramSocket(10010);
byte[] buff=new byte[1024];
//创建接收数据包
DatagramPacket recdp=new DatagramPacket(buff,buff.length);
//创建发送数据包
DatagramPacket senddp=null;
//接收来自客户端的数据包
socket.receive(recdp);
String line=null;
while((line=new String(recdp.getData(),0,recdp.getLength())) != null&&!("bye".equals(line))){
//打印来自客户端的信息
System.out.println("来自发送端的信息:"+line);
byte[]sendbuff=line.getBytes();
//发送数据包到客户端
senddp=new DatagramPacket(sendbuff,sendbuff.length,recdp.getAddress(),recdp.getPort());
socket.send(senddp);
//等待接收来自客户端的数据
socket.receive(recdp);
}
//关闭资源
socket.close();
System.out.println("接收端关闭");
}
}
(3)通过UDP实现群聊
/*
* 案例:通过UDP实现群聊
* 思路:
* 1.这个程序中既有收,又有发,需要同时执行,需要用到多线程技术
* 一个线程负责发送,一个线程负责接收
*/
public class UDPChatTest {
public static void main(String[] args) throws Exception {
//定义发送端socket
DatagramSocket sendDs=new DatagramSocket();
//定义接收端socket
DatagramSocket recDs=new DatagramSocket(10086);
//发送&接收
Send send=new Send(sendDs);
Receive rec=new Receive(recDs);
Thread t1=new Thread(send);
Thread t2=new Thread(rec);
//启动线程
t1.start();
t2.start();
}
}
/*
* 发送端代码
*/
public class Send implements Runnable {
private DatagramSocketds;
private DatagramPacketdp;
public Send(DatagramSocketds) {
this.ds =ds;
}
@Override
public void run() {
try{
//从键盘录入信息
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=br.readLine())!=null){
byte[]by=line.getBytes();
//实现局域网群聊,每个网段的最后一位如果写成255,没有此台主机,他会发往该网段的所有主机X.X.X.255
//dp=newDatagramPacket(by,by.length,InetAddress.getByName("192.168.1.255"),10086);
//发送信息到指定接收端
dp=new DatagramPacket(by,by.length,InetAddress.getByName("127.0.0.1"),10086);
ds.send(dp);
//输入over,则推出聊天
if("over".equals(line)){
System.out.println("关闭发送端");
break;
}
}
ds.close();
}
catch(Exceptione){
e.printStackTrace();
}
}
}
/*
* 接收端代码
*/
public class Receive implements Runnable {
private DatagramSocketds;
private DatagramPacketdp;
public Receive(DatagramSocketds) {
this.ds =ds;
}
@Override
public void run() {
while (true) {
try {
//接收发送到当前端口的数据
byte[]buff = newbyte[1024];
dp = new DatagramPacket(buff,buff.length);
ds.receive(dp);
//获取发送端Ip、端口号、内容等信息
String ip = dp.getAddress().getHostAddress();
intport = dp.getPort();
String content = new String(dp.getData(), 0,dp.getLength());
//打印信息到控制台
System.out.println(ip +":" + port +":" + content);
//如果接收到的信息是over,则关闭接收端
if("over".equals(content)){
System.out.println("关闭接收端");
break;
}
} catch (Exceptione) {
e.printStackTrace();
}
}
}
}
3.TCP传输控制协议
面向连接,可靠的协议
需要建立连接,所以效率低
通过三次握手建立连接
Socket:客户端socket
ServerSocket:服务器socket
TCP是面向连接的、可靠的传输协议,如果在没有服务端的情况下,客户端发送数据,会抛错,这种情况是不允许的
代码示例
(1)发送数据到服务端并显示
/*
* TCP实现客户端和服务端的收发过程
*
* 客户端的实现:发送信息到服务端,接收服务端返回的信息并显示
*/
public class TCPClient {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动...");
//创建客户端socket
Socket client=new Socket("127.0.0.1",10086);
//通过socket输出流发送数据
OutputStream out=client.getOutputStream();
out.write("服务器,你好".getBytes());
//读取服务器返回的数据,通过socket输入流
InputStream in=client.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
String content=new String(buf,0,len);
System.out.println(content);
//关闭资源
client.close();
}
}
/*
* 服务器端:接收来自客户端的数据,并发送信息到客户端
*/
public class TCPServer {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动");
//创建服务端socket
ServerSocket server=new ServerSocket(10086);
//获取客户端
Socket client=server.accept();
//读取客户端数据
InputStream in=client.getInputStream();
byte[] buff=new byte[1024];
int len=in.read(buff);
String content=new String(buff,0,len);
String ip=client.getInetAddress().getHostAddress();
System.out.println(ip+":"+content);
//给客户端发送数据
OutputStream out=client.getOutputStream();
out.write("你好,客户端".getBytes());
//关闭资源
client.close();
//如果是不断的获取客户端,则不需要关闭服务端
server.close();
}
}
(2)客户端和服务器之间的频繁通信
需求:
客户端通过键盘录入发送数据到服务端
服务端将接收到的数据显示到屏幕上的同时
将这些数据转换成大写发往客户端
当客户端输入over时,大写转换结束
注意:
数据不刷新的话,因为缓冲区,数据没有被发到服务器端
数据刷新后,数据可以被发到服务器端
但是服务器端readLine中带有缓冲区,没有读到行终止符,就一直在阻塞状态
方式1:手动加行终止符
PrintWriter pw = newPrintWriter(out);
pw.print(line+"\r\n");
pw.flush();
方式2:启用打印流的自动刷新
PrintWriter pw = newPrintWriter(out,true);
pw.println(line);
/*
* 客户端:
* 思路:
* 1.创建客户端socket,明确地址和端口
* 2.源:键盘录入,获取要转换的数据
* 3.目的:网络,Socket输出流
* 4.源:socket读取流,读取服务器发回来的大写数据
* 5.目的:控制台,显示大写数据
* 6.频繁的读写操作
* 7.关闭资源
*
*/
public class TCPClient {
public static void main(String[] args) throws Exception {
System.out.println("客户端运行");
// 获取目的端ip
InetAddress address = InetAddress.getByName("127.0.0.1");
// 创建客户端socket
Socket s = new Socket(address, 10086);
// 获取键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 获取socket读取流
OutputStream out = s.getOutputStream();
// BufferedWriter bout=newBufferedWriter(new OutputStreamWriter(out));
PrintWriter pw = new PrintWriter(out);
// 获取socket输出流
InputStream in = s.getInputStream();
BufferedReader bRead = new BufferedReader(new InputStreamReader(in));
// 频繁的读写操作
String line = null;
while ((line =br.readLine()) != null) {
pw.println(line);
if ("over".equals(line)) {
break;
}
String upper = bRead.readLine();
System.out.println(upper);
}
// 关闭资源
br.close();
s.close();
}
}
/*
* 服务端:
* 思路:
* 1.创建服务端socket,监听一个端口
* 2.源:socket输入流,读取客户端发来的数据
* 3.目的:socket输出流,将转成大写的数据发送给客户端
* 4.频繁的读写资源
* 5.关闭客户端
*/
public class TCPServer {
public static void main(String[] args) throws Exception {
System.out.println("服务端运行...");
// 创建服务器socket
ServerSocket ss =new ServerSocket(10086);
while (true) {
// 获取客户端对象
Socket s = ss.accept();
//打印客户端IP
System.out.println(s.getInetAddress().getHostAddress()+"....connected");
// socket输入流
BufferedReader bin = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// socket输出流
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
// 频繁的读写操作
String line = null;
while ((line =bin.readLine()) != null) {
System.out.println(line);
if("over".equals(line)){
break;
}
// 转换大写,发送给客户端
pw.println(line.toUpperCase());
pw.flush();
}
s.close();
}
}
}
(3)TCP实现图片上传
/*
* 客户端:上传图片到服务端,获取服务端发来的上传结果并显示
*/
public class Client {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动...");
// 创建客户端socket
Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 10010);
// 获取socket输出流
BufferedOutputStream bos =new BufferedOutputStream(s.getOutputStream());
// 读取要上传的文件
BufferedInputStream bis =new BufferedInputStream(new FileInputStream(
"D:\\1.jpg"));
byte[] b = new byte[2048];
int len;
// 上传文件
while ((len =bis.read(b)) != -1) {
bos.write(b, 0,len);
}
// 向服务端发送了一个结束标记,让服务端结束读取的动作
s.shutdownOutput();
// 获取从服务器端发来的上传成功的信息
InputStream in = s.getInputStream();
byte[] b2 = new byte[1024];
int len2 = in.read(b2);
System.out.println(new String(b2, 0,len2));
// 关闭资源
bis.close();
s.close();
System.out.println("客户端关闭");
}
}
/*
* 服务端:接收客户端发送来的上传文件,存到指定目录中
* 为防止出现同名覆盖,文件名=客户端ip+编号
* 操作成功,发送“上传成功”到客户端
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动..");
// 创建服务器socket
ServerSocket ss =new ServerSocket(10010);
while (true) {
// 获取客户端socket
Socket s = ss.accept();
//打印客户端IP
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"...conneced");
// 获取socket输入流
BufferedInputStream bis =newBufferedInputStream(
s.getInputStream());
//新建File对象,指向目的文件夹
File dir=new File("D:\\uploadTest");
//目的文件夹不存在,则创建
if(!dir.exists()){
dir.mkdir();
}
//解决上传文件的重名覆盖问题
int count=1;
File desc=new File(dir,ip+"("+count+").jpg");
while(desc.exists()){
count++;
desc=new File(dir,ip+"("+count+").jpg");
}
// 创建输出流,指向目的地址
BufferedOutputStream bos =new BufferedOutputStream(
new FileOutputStream(desc));
// 复制文件
byte[]b = newbyte[2048];
int len;
while ((len =bis.read(b)) != -1) {
bos.write(b, 0,len);
}
// 向客户端发送上传成功的信息
OutputStream out = s.getOutputStream();
out.write("上传成功!".getBytes());
// 关闭资源
bos.close();
s.close();
}
}
}
(4)多客户端并发上传
实现多客户端的并发上传,客户端代码不需变动,服务端必须启动多个线程来实现
/*
* 客户端
*/
public class Client {
public static void main(String[] args) throws Exception {
System.out.println("客户端启动...");
// 创建客户端socket
Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 10010);
// 获取socket输出流
BufferedOutputStream bos =new BufferedOutputStream(s.getOutputStream());
// 读取要上传的文件
BufferedInputStream bis =new BufferedInputStream(new FileInputStream(
"D:\\1.jpg"));
byte[] b = new byte[2048];
int len;
// 上传文件
while ((len =bis.read(b)) != -1) {
bos.write(b, 0,len);
}
// 向服务端发送了一个结束标记,让服务端结束读取的动作
s.shutdownOutput();
// 获取从服务器端发来的上传成功的信息
InputStream in = s.getInputStream();
byte[] b2 = new byte[1024];
int len2 = in.read(b2);
System.out.println(new String(b2, 0,len2));
// 关闭资源
bis.close();
s.close();
System.out.println("客户端关闭");
}
}
/*
* 要想实现多个客户端并发上传,服务器必须启动多个线程来完成
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动..");
// 创建服务器socket
ServerSocket ss =new ServerSocket(10010);
while (true) {
// 获取客户端socket
Socket s = ss.accept();
//将客户端socket封装进Upload,启动线程
new Thread(new Upload(s)).start();
}
}
}
/*
* 实现上传的方法
*/
public class Upload implements Runnable {
private Sockets;
public Upload(Sockets) {
this.s =s;
}
@Override
public void run() {
try {
// 打印客户端IP
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip +"...conneced");
// 获取socket输入流
BufferedInputStream bis =newBufferedInputStream(
s.getInputStream());
// 新建File对象,指向目的文件夹
File dir = new File("D:\\uploadTest");
// 目的文件夹不存在,则创建
if (!dir.exists()) {
dir.mkdir();
}
// 解决上传文件的重名覆盖问题
int count = 1;
File desc = new File(dir,ip + "(" + count + ").jpg");
while (desc.exists()) {
count++;
desc = new File(dir,ip + "(" + count + ").jpg");
}
// 创建输出流,指向目的地址
BufferedOutputStream bos =new BufferedOutputStream(
new FileOutputStream(desc));
// 复制文件
byte[]b = newbyte[2048];
int len;
while ((len =bis.read(b)) != -1) {
bos.write(b, 0,len);
}
// 向客户端发送上传成功的信息
OutputStream out = s.getOutputStream();
out.write("上传成功!".getBytes());
// 关闭资源
bos.close();
s.close();
} catch (Exceptione) {
e.printStackTrace();
}
}
}