——- android培训、java培训、期待与您交流! ———-
网络参考模型
InetAddress对象
InetAddress对象的方法
此方法不能不能new对象。获取对象时只能通过该对象中的静态方法获取
static InetAddress getByName(String host) 获取指定主机名称的地址对象
static InetAddress getLocalHost() 获取本地主机的地址对象
String getHostName() 获取主机名称
String getHostAddress() 获取主机地址 (此方法重点掌握)
String toString() 获取主机名称+主机地址
代码示例:
/*
InetAddress对象演示
*/
import java.net.*;
public class Demo {
public static void main(String[] args) throws UnknownHostException {
// InetAddress ia = InetAddress.getLocalHost();//获取本地主机,会抛出UnknownHostException未知主机异常
// System.out.println(ia.toString());//MS-20150515DCSJ/192.168.61.216 获取名字和地址
// System.out.println(ia.getHostAddress());//192.168.61.216 获取主机地址
// System.out.println(ia.getHostName());//MS-20150515DCSJ 获取主机名称
//
InetAddress ia = InetAddress.getByName("www.baidu.com");//获取baidu这个主机
System.out.println(ia.getHostAddress());//61.135.169.121 获取百度主机地址
System.out.println(ia.getHostName());//www.baidu.com 获取百度主机名称
// InetAddress[] ia = InetAddress.getAllByName("www.hao123.com");//百度的主机不是只有一个
// for(InetAddress i : ia)
// System.out.println(i.getHostAddress()+"..."+i.getHostName());
}
}
UDP和TCP特点
UDP
1,面向无连接
2,数据封包,数据大小限制带64k内
3,是不可靠协议
4,传输速度快
哪些属于udp传输:聊天
TCP
1,面向连接
2,大数据量传输
3,是可靠协议
4,因为需要连接,所以效率低
哪些数据tcp传输:下载
如何写一个UDP传输程序
定义一个udp发送端
思路:
1,建立udp socket服务。
2,提供数据,将数据封装到数据包中。
3,通过socket服务器的发送功能send,将数据包发出去
4,关闭资源
class Demo {// 发送端
public static void main(String[] args) throws Exception {
// System.out.println(InetAddress.getLocalHost().getHostAddress());//获取本机的地址
// 1,创建udp服务。通过DatagramSocked对象。
DatagramSocket ds = new DatagramSocket(8888);//定义本服务的端口为8888
// 2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress
// address, int port);
byte[] buf = "data ge men lai le".getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getByName("192.168.61.0"), 10000);//InetAddress.getByName("192.168.61.33")为
//获取对方的主机名。10000是指要将数据发送到"192.168.61.33"主机的哪个应用程序上,既要发送到对方主机的哪个端口
// 3,通过socket服务,将已有的数据包发送出去。通过send方法。
ds.send(dp);
//4,关闭资源
ds.close();
}
}
定义udp的接收端
思路:
1,定义udp socket服务。通常会监听一个窗口。其实就是给这个接收网络应用程序定义数字标识。
方便于明确哪些数据过来该应用程序可以处理
2,定义一个数据包,因为要存储接收到的字节数据。
因为数据包对象中有更多功能,可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将接收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
5,关闭资源
class Demo2 {//接收端
public static void main(String[] args) throws Exception {
// 1,创建udp服务。通过DatagramSocked对象。
DatagramSocket ds = new DatagramSocket(10000);//创建udp服务同时,并指定此程序端口为10000,以便接收发送过来的数据。
//当这句话连续运行两次时,会出现绑定异常BindException
//2,定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3,通过socket服务,将接收到的数据存入数据包中。通过receive方法。
ds.receive(dp);//此方法是阻塞式的方法,如果没有收到数据,程序则停在此处等待。当接收到数据时,程序就往下执行
//4,通过数据包的方法获取其中的数据
InetAddress ia = dp.getAddress();//获取发送端的地址对象
String ip = ia.getHostAddress();//通过地址对象获取发送端的ip地址
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();//获取发送端的 端口
System.out.println(ip+"::"+data+"::"+port);//192.168.61.0::data ge men lai le::8888
//5,关闭资源
ds.close();
}
}
定义一个类似于聊天工具的软件
一边不断输入数据,而另一边不断读取数据
代码示例:
import java.io.*;
import java.net.*;
class Demo {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
while(true){
String line = bufr.readLine();
if(line.equals("886"))
break;
byte[] buf = line.getBytes();
//将数据封装进数据包中
DatagramPacket dp = new DatagramPacket(buf, buf.length,InetAddress.getByName(InetAddress.getLocalHost().getHostAddress()),10101);
//将数据包发送出去
ds.send(dp);
}
ds.close();
}
}
class Demo3 {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(10101);
while(true){
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());
System.out.println(ip+"..."+data);
}
}
}
多线程实现UDP传输
import java.io.*;
import java.net.*;
class Send implements Runnable {
private DatagramSocket ds;
public Send(DatagramSocket ds) {
this.ds = ds;
}
public void run() {
try {
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
while (true) {
String line = bufr.readLine();
if (line.equals("over"))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getByName("192.168.61.255"), 10002);//地址为192.168.61.255。255是广播地址,可以给所有局域网发送数据
ds.send(dp);
}
} catch (Exception e) {
throw new RuntimeException("发送端异常");
}
}
}
class Receive implements Runnable {
DatagramSocket ds;
public Receive(DatagramSocket ds){
this.ds = ds;
}
public void run() {
while (true) {
try {
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());
System.out.println(ip+"::"+data);
} catch (Exception e) {
throw new RuntimeException("接收端异常");
}
}
}
}
class Demo {
public static void main(String[] args) throws Exception {
DatagramSocket ds_send = new DatagramSocket();
DatagramSocket ds_receive = new DatagramSocket(10002);
new Thread(new Send(ds_send)).start();
new Thread(new Receive(ds_receive)).start();
}
}
如何写一个TCP传输程序
1,tcp分客户端和服务端
2,客户端对应的对象是Socket。服务端对应的对象是ServerSocket.
客户端:
通过查阅Socket对象,发现在该对象创建时,就可以去连接指定主机。
因为tcp是面向连接的。所以在建立Socket服务时,
就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
步骤:
1,创建Socket服务。并指定要连接的主机端口
2,为了发送数据,应该获取Socket流中的输出流
3,发送数据
import java.io.*;
import java.net.*;
class Demo {//客户端
public static void main(String[] args) throws Exception {
//创建客户端的Socket服务。指定目的主机和窗口
Socket s = new Socket("192.168.61.216",10004);
//为了发送数据,应该获取Socket流中的输出流
OutputStream out = s.getOutputStream();
out.write("tcp ge men lai la".getBytes());//给服务端发送一行数据
s.close();//没有必要关闭out流。因为out流是通过Socket创建的。所以只要关闭Socket就可以了
}
}
服务端:
1,建立服务端的Socket服务。ServerSocket(),并监听一个窗口
2,获取连接过来的客户端对象。
通过ServerSocket的accept方法。没有连接就会等,所以这个方法是阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,
并获取到该客户端对象的读取流来读取发过来的数据,并打印在控制台上
4,关闭服务器(可选)
class Demo2{//服务端
public static void main(String[] args) throws Exception {
//创建服务端ServerSocket。并监听一个端口
ServerSocket ss = new ServerSocket(10004);
//通过accept方法获取连接过来的客户端对象
Socket s = ss.accept();//此方法时阻塞的,如果没有链接就会等待
//获取客户端的ip地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据
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的传输的客户端和服务端互访
/*
需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
*/
import java.io.*;
import java.net.*;
/*
客户端:
1,建立Socket服务,指定要连接主机和端口
2,获取Socket流中的输出流。将数据写入到该流中。通过网络发送给服务端
3,获取Socket流中的输入流,将服务端反馈的数据获取到,并打印
4,关闭客户端资源
*/
class Demo {//客户端
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.61.216",9999);
OutputStream os = s.getOutputStream();
os.write("客户端:我发送数据啦".getBytes());//给服务端发送信息
InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);//当给服务端发出信息后,在此处会等待服务端的反馈,如果服务端没有反馈,那么程序会留在此等待,当客户端反馈数据后,程序再往下执行
System.out.println(new String(buf,0,len));
s.close();
}
}
/*
服务端:
1,建立服务端ServerSocket,并接收客户端的端口
2,获取客户端的对象
3,再获取客户端对象中的读取流,读取客户端发送的信息
4,获取客户端对象中的输出流,将服务端的信息反馈给客户端
*/
class Demo2{//服务端
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();//获取客户端的对象。如果客户端没有发送数据,那么程序将会停留在此等待,等待客户端发送的数据,当接收到数据后再往下执行
String ip = s.getInetAddress().getHostAddress();//输出客户端的地址
InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);//读取客户端的信息,并输出
System.out.println(new String(buf,0,len));
OutputStream os = s.getOutputStream();
Thread.sleep(4000);
os.write("服务端:收到数据啦".getBytes());//服务端返回信息给客户端
s.close();
ss.close();
}
}
TCP传输容易引发错误的代码:客户端和服务端都在莫名的等待
/*
需求:建立一个文本转换服务器。
客户端给服务端发送文本,服务端会将文本转换成大写再返回给客户端。
而且客户端可以不断的发送文本。当客户端输入over时,转换结束
客户端:
既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
源:键盘录入
目的:网络设备,网络输出流
而且操作的是文本数据,可以选择字符流。
步骤:
1,建立服务
2,获取键盘录入
3,将数据发给服务端
4,获取服务端返回的大写数据
5,结束。关闭资源
都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲区
*/
import java.awt.Container;
import java.io.*;
import java.net.*;
//客户端
class Demo {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.61.0", 11111);
// 定义读取键盘数据的流对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
// 定义目的,将数据写入到socket输出流。发给服务端
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 定义一个Socket读取流,读取服务端返回的大写信息
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
String line = null;
while ((line = bufr.readLine()) != null) {
if (line.equals("over"))
break;
bufOut.write(line);
bufOut.newLine();//如果将此行注释掉,会导致程序莫名等待。因为服务端的bufIn.readLine()方法读取数据时,
//是以换行符判断是否是一行数据。如果此处不添加换行,会导致服务端的bufIn.readLine()方法就不认为是一行数据,
//从而导致服务端bufIn.readLine()方法读取不到换行符,从而导致服务端莫名等待
bufOut.flush();//如果将此行注释掉,会导致程序莫名等待。因为客户端没有将缓冲区中的数据刷新出去,
//导致数据依然存在缓冲区中而没有发送给服务端。导致服务端的bufIn.readLine()方法读不到数据。
//从而导致程序等待
String str = bufIn.readLine();
System.out.println("Server:" + str);
}
s.close();
bufr.close();
}
}
/*
服务端:
源:socket读取流
目的:socket输出流 都是文本,需要缓冲
*/
class Demo2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(11111);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress());
// 读取socket读取流中的数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 目的,socket输出流。将大写数据写入到socket输出流,并发给客户端
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
String line = null;
while ((line = bufIn.readLine()) != null) {
System.out.println(line);
bufOut.write(line.toUpperCase());
bufOut.newLine();//如果将此行注释,会导致程序莫名等待。因为客户端的bufIn.readLine()方法读取数据时,
//判断是否有换行符,如果没有换行符,那么客户端的bufIn.readLine()方法就不认为是一行数据,
//从而导致客户端bufIn.readLine()方法读取不到换行符,从而导致客户端莫名等待
bufOut.flush();//如果此行被注释,会导致程序莫名的等待。因为数据还存储在缓冲区中,
//并没有发送到客户端,会导致客户端的bufIn.readLine()方法读不到数据。
//从而导致客户端在等待服务端发送数据。所以必须要进行刷新的动作
}
s.close();
ss.close();
}
}
/*
将以上代码修改为更简便的代码
*/
import java.awt.Container;
import java.io.*;
import java.net.*;
//客户端
class Demo {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.61.0", 11111);
// 定义读取键盘数据的流对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
// 定义目的,将数据写入到socket输出流。发给服务端
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 定义一个打印流接收Socket读取流,并且设置为自动刷新
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while ((line = bufr.readLine()) != null) {
if (line.equals("over"))
break;
out.println(line);//将数据打印为服务端。打印过去时,就已经具备换行和刷新
String str = bufIn.readLine();
System.out.println("Server:" + str);
}
s.close();
bufr.close();
}
}
//服务端:
class Demo2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(11111);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress());
// 读取socket读取流中的数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 定义一个打印流接收Socket读取流,并且设置为自动刷新
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while ((line = bufIn.readLine()) != null) {
System.out.println(line);
out.println(line.toUpperCase()); //将数据打印为客户端。打印过去时,就已经具备换行和刷新
}
s.close();
ss.close();
}
}
/*
需求:在客户端发送一个文件给服务端
服务端再将客户端的数据存入到一个文件中
*/
import java.awt.Container;
import java.io.*;
import java.net.*;
/*
客户端:
源:一个文件
目的:socket中的输出流
*/
class Demo {
public static void main(String[] args) throws Exception {
System.out.println(InetAddress.getLocalHost());
Socket s = new Socket("172.17.64.78", 9999);
//创建一个读取流,用来读取将要发送的文件
BufferedReader bufr = new BufferedReader(new FileReader("D:\\Demo.java"));
//创一个socket输出流,将文件发送到服务端
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//创建一个socket读取流,读取服务端发送过来的数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufr.readLine())!=null){
out.println(line);
}
s.shutdownOutput();//关闭客户端的输入流。相当于给流中加入一个结束标记-1。如果不加入此行代码,导致服务端认为还有数据要传输而进行等待
String str = bufIn.readLine();// 代码1
System.out.println(str);// 代码2
bufr.close();
out.close();
s.close();
}
}
/*
服务端:
源:socket中的输出流,用Reader
目的:一个文件,用Reader
*/
class Demo2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9999);//创建服务端
Socket s = ss.accept();//获取客户端
System.out.println(s.getInetAddress().getHostAddress());
//定义一个socket读取流,用来读取客户端发送的信息
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//定义一个输出流,将文件保存在 服务端
PrintWriter pw = new PrintWriter(new FileWriter("D:\\abccc.txt"),true);
String line = null;
while((line = bufIn.readLine())!=null){//如果客户端没有s.shutdownOutput()此行代码,那么客户端发送数据完毕后,服务端并不知道客户端已经发送完毕,
//那么服务端bufIn.readLine()就不会读取到null,从而导致程序在此等待。
//如果将客户端的s.shutdownOutput(),以及代码1,代码2都注释掉,程序就不会等待。因为,客户端的bufr.readLine()读到null后,
//就执行s.close()直接将Socket关闭了,就算服务端bufIn.readLine()方法读取不到null,也强制将服务端关闭,从而使程序正常运行。
pw.println(line);
}
//定义一个socket中的输出流,用来反馈给客户端信息
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.write("数据传输完毕");
out.close();
s.close();
ss.close();
}
}
多线程实现TCP的图片传输
import java.io.*;
import java.net.*;
import javax.management.RuntimeErrorException;
/*
客户端:
1,建立服务端点
2,读取客户端已有的图片数据
3,通过Socket输出流将数据发给服务端
4,读取服务端的反馈信息
5,关闭
*/
public class Demo {
public static void main(String[] args) throws Exception {
// System.out.println(InetAddress.getLocalHost());
if (args.length != 1) {
System.out.println("选择一个png格式的图片");
return;
}
File file = new File(args[0]); //使用主函数中的数组接收参数的形式来读取要输入的文件
if (!(file.exists() && file.isFile())) {
System.out.println("该文件有 问题,要么不存在,要么不是文件");
return;
}
if (file.getName().endsWith(".jpg")) {
System.out.println("文件的格式错误,选择jpg文件");
return;
}
if (file.length() > 1024 * 1024 * 5) {
System.out.println("文件过大");
return;
}
Socket s = new Socket("172.17.65.128", 10002);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
file));
BufferedInputStream in = new BufferedInputStream(s.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());
byte[] buf = new byte[1024];
int len = 0;
while ((len = bis.read(buf)) != -1) {
out.write(buf, 0, len);
out.flush();
}
// 告诉服务端数据已写完
s.shutdownOutput();
byte[] bufby = new byte[1024];
int num = in.read(bufby);
System.out.println(new String(bufby, 0, num));
bis.close();
s.close();
}
}
/*
服务端:
那么为了可以让多个客户端并发访问服务端。
那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端的请求。
如何定义线程呢? 只要明确了每一个客户端在服务端执行的代码即可。将该代码存入run方法中
*/
class Demo2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10002);
while (true) {
Socket s = ss.accept();//当主线程执行到这里时,等待客户端的连接。当客户端连接后,主线程往下执行,并创建了一个新的线程进行图片的传输。
//然后主线程再循环回到这里,等待下一个客户端的连接,当客户端再连接进时,主线程又在开启了一个新的线程进行图片的传输
new Thread(new ServerThread(s)).start();
}
}
}
class ServerThread implements Runnable {
Socket s;
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
int count = 1;
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....连接进来");
File file = new File("D:\\" + ip + "(" + (count++) + ").png");
while (file.exists())
// 如果发送的图片已经存在,那么图片的代号自动自动加一,这样做是为了保证文件的名字没有重复
file = new File("D:\\" + ip + "(" + (count++) + ").png");
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(file));
PrintStream out = new PrintStream(s.getOutputStream());
BufferedInputStream in = new BufferedInputStream(s.getInputStream());
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
out.write("上传成功".getBytes());
System.out.println(ip + "传送过来一个图片");
bos.close();
s.close();
} catch (Exception e) {
throw new RuntimeException(ip + "上传失败");
}
}
}
练习:客户端通过键盘录入用户名服务端对这个用户名进行校验
客户端通过键盘录入用户名
服务端对这个用户名进行校验
如果用户名已存在,在服务端显示,xxx,已登录。
并在客户端显示,xxx,欢迎光临。
如果该用户不存在,在服务端显示,xxx,尝试登陆。
并在客户端显示,xxx,该用户不存在
最多就登陆三次
代码示例
import java.io.*;
import java.net.*;
import javax.management.RuntimeErrorException;
import org.xml.sax.InputSource;
//客户端
public class Demo {
public static void main(String[] args) throws Exception {
// System.out.println(InetAddress.getLocalHost());
Socket s = new Socket("172.17.65.128", 10004);
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
s.getInputStream()));
for (int i = 0; i < 3; i++) {
String line = bufr.readLine();
if (line == null)// 相当于强制结束了程序,所以没有必要再继续执行判断了
break;
out.println(line);
String info = in.readLine();
System.out.println(info);
if (info.contains("欢迎"))
break;
}
s.shutdownOutput();
bufr.close();
s.close();
}
}
//服务端
class Demo2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10004);
while (true) {
Socket s = ss.accept();
new Thread(new ServerThread(s)).start();
}
}
}
class ServerThread implements Runnable {
Socket s;
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "...connect");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
for (int i = 0; i < 3; i++) {
BufferedReader bufr = new BufferedReader(new FileReader("D:\\urse.txt"));//此处代码必须放在for循环内,因为如果放在for循环外,
//那么执行while循环时,此方法的指针已经指向了末尾,指针的值为null,那么导致下一次读取文件时,读到的数值都是null
String name = in.readLine();
String line = null;
boolean flag = false;
while ((line = bufr.readLine()) != null) {
if (line.equals(name)) {
flag = true;
break;
}
}
if (flag) {
System.out.println(name + ",已登录");
out.println(name + ",欢迎光临");
break;
} else {
System.out.println(name + ",尝试登陆");
out.println(name + ",用户名不存在");
}
}
s.close();
} catch (Exception e) {
throw new RuntimeException(ip + "校验失败");
}
}
}
/*
程序使用说明
在D盘下创建一个urse.txt文件。并在文件中写入
zhangsan
lisi
wangwu
然后保存文件,再运行该程序,输入一个用户名,判断该用户名是否在urse.txt文件中已存在
*/
URL和URLConnection对象
URL中的方法
String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getProtocol()
获取此 URL 的协议名称。
String getQuery()
获取此 URL 的查询部分。
/*
URP方法演示
*/
import java.io.*;
import java.net.*;
import javax.management.RuntimeErrorException;
import org.xml.sax.InputSource;
public class Demo {
public static void main(String[] args) throws Exception {
URL url = new URL("http://172.17.65.128:8080/myweb/demo.html?name=haha&age=33");
System.out.println("getProtocol() :"+url.getProtocol());// getProtocol() :http
System.out.println("getHost() :"+url.getHost());// getHost() :172.17.65.128
System.out.println("getPort() :"+url.getPort());// getPort() :8080
System.out.println("getPath() :"+url.getPath());// getPath() :/myweb/demo.html
System.out.println("getFile() :"+url.getFile());// getFile() :/myweb/demo.html?name=haha&age=33
System.out.println("getQuery() :"+url.getQuery());// getQuery() :name=haha&age=33
}
}
import java.io.*;
import java.net.*;
import javax.management.RuntimeErrorException;
import org.xml.sax.InputSource;
public class Demo {
public static void main(String[] args) throws Exception {
//System.out.println(InetAddress.getLocalHost());
URL url = new URL("http://192.168.61.216:10102");
URLConnection conn = url.openConnection();//获取url对象的url连接器对象,将连接封装成了对象
InputStream in = conn.getInputStream();//获取读取流,可以将服务端反馈的数据读出来。如果服务端没有反馈的数据,会出现异常
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1){
System.out.println(new String(buf,0,len));//<font color='red' size='7'>客户端你好</font>
}
}
}
class Demo2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10102);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("<font color='red' size='7'>客户端你好</font>");
s.close();
ss.close();
}
}
总结
udp
在udp运行时,需要先运行接收端,因为接收端需要接收发送端发送的数据。
如果先运行发送端,那么发送端发送数据时,接收端有可能接收不到。
因为udp是不可靠的协议,会导致数据丢失
udp的发送数据就好比对讲机,对讲机需要互相讲话,
就必须要两个人都打开对讲机才能够说话。
如果A打开对讲机,B没有打开对讲机,那么A讲话时B不可能接收的到数据,
这就导致了A的数据丢失,所以说udp是不可靠的协议。
在接收端中,receive方法是一个阻塞方法。当发送端的数据通过send方法发送给接收端时,接收端中receive方法才会继续往下执行。
代码示例
import java.net.*;
//发送端
public class Demo {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
byte[] buf = "这是一条数据".getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getLocalHost(), 10001);
System.out.println("发送端:时隔3秒发送数据");
Thread.sleep(3000);
ds.send(dp);// 将数据包中的数据发送给接收端。如果将此行注释,那么接收端会永远等待下去,因为接收端没有收到数据
System.out.println("发送端:数据已经发送");
ds.close();
}
}
// 接收端
class Demo2 {
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);
System.out.println("接收端:等待发送端发送数据");
ds.receive(dp);// 将接收到的数据存入dp中,既存入数据包中。当发送端没有发送数据时,则等待客户端发送
System.out.println("接收端:收到数据");
String ip = dp.getAddress().getHostAddress();// 获取发送端地址
byte[] data = dp.getData();// 获取发送端发送的数据
int len = dp.getLength();// 获取发送端发送数据的长度
System.out.println(ip + "..." + new String(data, 0, len));
}
}
tcp
tcp在运行时,先运行服务端。当服务端运行到Socket s = ss.accept()方法时,服务端会进入等待,
等待客户端与服务端建立连接,当客户端开始运行时并与服务端建立连接,服务端的程序才会继续向下执行。
由此可知:
服务端的accept方式是阻塞式的方法。当客户端没有连接到服务端时,服务端只能在accept处等待客户端的连接
代码示例
import java.io.*;
import java.net.*;
//客户端
class Demo {
public static void main(String[] args) throws Exception {
Socket s = new Socket("172.17.64.78", 9998);
}
}
//服务端
class Demo2{
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9998);
System.out.println("服务端...等待...与客户端连接");
Socket s = ss.accept();
System.out.println("服务端与客户端连接成功啦");
}
}
当客户端与服务端进行连接后,服务端开始继续执行,当服务端执行到read()方法读取客户端的数据时,
服务端又会再次进行等待,等待客户端给服务端发送数据。等客户端发送数据后,服务端的read方法收到客户端的数据时,
程序又会再次向下执行。
由此可知:
服务端读取客户端的read方法也是阻塞式方法。当客户端没有发送数据时,服务端只能等待客户端的数据,只有收到数据后才会往下执行
代码示例
import java.io.*;
import java.net.*;
//客户端
class Demo {
public static void main(String[] args) throws Exception {
System.out.println(InetAddress.getLocalHost());
Socket s = new Socket("172.17.64.78", 9997);
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
Thread.sleep(3000);//时隔3秒发送第一条数据
String str1 = "数据..1";
bufOut.write(str1);
bufOut.newLine();
bufOut.flush();
Thread.sleep(3000);//时隔3秒发送第二条数据
String str2 = "数据..2";
bufOut.write(str2);
bufOut.flush();
s.close();
}
}
//服务端
class Demo2{
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9997);
System.out.println("服务端...等待...与客户端连接");
Socket s = ss.accept();
System.out.println("服务端与客户端连接成功啦");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufIn.readLine())!=null){//当客户端运行后,此处等待客户端发送的数据。客户端时隔3秒发送,此处则时隔3秒读取一次
System.out.println("服务端...+"+line+"...收到数据啦");
}
ss.close();
}
}
当客户端给服务端发送数据后,客户端需要用read方法读取服务端的反馈数据,
当服务端没有反馈数据时,客户端只能进入等待状态,
等待服务端给客户端反馈数据。当客户端收到服务端的反馈数据后,
服务端才会继续向下执行。
由此可知:
客户端使用read方法读取服务端的反馈数据也是阻塞式方法。服务端没有发送数据,客户端只能进行等待
在使用tcp进行传输数据时,需要注意数据的刷新,否则会很容易造成客户端给服务端发送数据后,而服务端读取不到数据。
或者服务端反馈数据时,客户端收不到服务端的反馈。
代码示例
import java.io.*;
import java.net.*;
//客户端
class Demo {
public static void main(String[] args) throws Exception {
System.out.println(InetAddress.getLocalHost());
Socket s = new Socket("172.17.64.78", 9997);
BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String str1 = "数据..1";
bufOut.write(str1);
bufOut.newLine();
//bufOut.flush(); //将自动刷新注释掉,那么服务端就无法读取到数据,因为数据保存在缓冲区中,并没有发送出去
String str2 = "数据..2";
bufOut.write(str2);
bufOut.newLine();
//bufOut.flush(); //将自动刷新注释掉,那么服务端就无法读取到数据,因为数据保存在缓冲区中,并没有发送出去
s.close();
}
}
//服务端
class Demo2{
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9997);
System.out.println("服务端...等待...与客户端连接");
Socket s = ss.accept();
System.out.println("服务端与客户端连接成功啦");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufIn.readLine())!=null){
System.out.println("服务端...+"+line+"...收到数据啦");
}
ss.close();
}
}