1.网络模型:
OSI参考模型、TCP/IP参考模型
数据传输的过程:向下走:封包 向上走:拆包
向上走一直拆包,直到得到数据。
2.网络通讯要素
ip地址、端口号、传输协议
Ip和端口用来找对方,确认对方身份。协议保证双方都能听懂双方的对话,常见的传输协议是:TCP、UDP
更多网络信息参考网络相关书籍和教程。
3.常用类InetAddress,此类表示互联网协议 (IP) 地址
得到InetAddress对象的几种方法:得到本地Host;通过ip;通过域名
public static void main(String[] args) throws Exception {
//1.通过InetAddress.getLocalHost()得到本机InetAddress对象
/*InetAddress host = InetAddress.getLocalHost();//主机名+ip
System.out.println(host);//Lenovo-PC/192.168.159.10 主机名+ip
System.out.println(host.getHostAddress());//ip
System.out.println(host.getHostName());// 主机名
*/
//2.通过InetAddress的静态方法,传入ip得到InetAddress对象
/*InetAddress host = InetAddress.getByName("192.168.159.1");
System.out.println(host.getHostAddress());//ip
System.out.println(host.getHostName());//主机名
*/
//3.通过域名得到InetAddress对象数组
InetAddress[] is = InetAddress.getAllByName("www.baidu.com");
System.out.println(is.length);//2
System.out.println(is[0].getHostName());//www.baidu.com 得到域名
System.out.println(is[1].getHostName());
}
TCP、UDP、Socket
1.TCP与UDP的区别
(1)TCP
建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必需建立连接,所以效率低。
(2)UDP
将数据,源和目的封装成包,不需要建立连接;每个数据报的大小限制在64K内;因为不需要建立连接,所以是不可靠的传输;不需要建立连接,所以速度快。
2.Socket
Socket是为网络服务提供的一种机制;通信两段都有Socket,网络通信实际上就是Socket通信;数据在Socket间的通信是通过IO实现的。
3.UDP传输
(1)UDP收发数据使用的是DatagramSocket。数据需要封装成包DatagramPacket,需要建立发送端和接收端,这两个端是相互独立的程序。
(2)InetAddress/SocketAddress区别
InetAddress指的是IP,SocketAddress是封装了ip和端口的抽象类
(3)网络编程使用的包是java.net。一般net需要和io包一起使用。
(4)建立服务连接的DatagramSocket的创建不放在while中,会发生绑定异常.建立Socket相当于建立连接,连接只需要建立一次,如果没有断开又建立连接也会发生异常,所以建立连接Socket的创建是唯一的。
(5)因为UDP传输的两端是相互独立的程序,所以要建立两个main,启动的时候先启动接收端,再启动发送端。
(6)发送端Socket可以关闭,一般接收端Socket不用关闭
键盘发送数据的例子:
发送端要指明接收端的ip,端口。发送端的端口是随机分配的,也可以自己指定.接收端要指明接收的端口号,接收端除了可以获得数据,还可以得到发送端的ip,端口。
自己指定发送端端口号:
DatagramSocket ds = new DatagramSocket(8888);
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
(**)发送端是键盘输入,所以不用while(true)
//发送端
public class SendClass {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine())!= null){//readLine是一个阻塞式的方法
if("over".equals(line)){
break;
}
byte[] b = line.getBytes();
DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("127.0.0.1"),10001);
ds.send(dp);
}
ds.close();
}
}
(**)接收端需要进行while(true),接收端的连接不用关闭
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ReciveClass {
public static void main(String[] args) throws Exception{
//指明用哪个端口接收
DatagramSocket ds = new DatagramSocket(10001);
//接收端一般就是一直的while(true)
while(true){
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b,b.length);
ds.receive(dp);
//打印接收到的发送端的数据
String ip = dp.getAddress().getHostAddress();//打印发送端的ip
String data = new String(dp.getData(),0,dp.getLength());//打印发送端的数据
int port = dp.getPort();//打印发送端的端口
System.out.println("ip:"+ip+",data:"+data+",port:"+port);
}
}
}
使用线程键盘发送数据的例子:(注意:是单独的程序)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Send implements Runnable {
DatagramSocket ds = null;
public Send(DatagramSocket ds){
this.ds = ds;
}
@Override
public void run() {
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine())!= null){//readLine是一个阻塞式的方法
if("over".equals(line)){//但是发送端结束了,接收端还会一直接收,阻塞着
break;
}
byte[] b = line.getBytes();
DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("127.0.0.1"),10002);
ds.send(dp);
}
}catch(Exception e){
throw new RuntimeException("发送端失败");
}finally{ds.close();}
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Recive implements Runnable {
DatagramSocket ds = null;
public Recive(DatagramSocket ds){
this.ds = ds;
}
@Override
public void run() {
try{
while(true){
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b,b.length);
ds.receive(dp);
//打印接收到的发送端的数据
String ip = dp.getAddress().getHostAddress();//打印发送端的ip
String data = new String(dp.getData(),0,dp.getLength());//打印发送端的数据
int port = dp.getPort();//打印发送端的端口
System.out.println("ip:"+ip+",data:"+data+",port:"+port);
}
}catch(Exception e){
throw new RuntimeException("接收端失败");
}
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Test{
public static void main(String[] args) throws Exception {
DatagramSocket sendS = new DatagramSocket();//发送端与接收端使用的Socket是不同的,两端各自有一个
DatagramSocket reciveS = new DatagramSocket(10002);
new Thread(new Send(sendS)).start();
new Thread(new Recive(reciveS)).start();
}
}
4.TCP传输
(1)需要客户端和服务端,是两个独立的程序。客户端使用Socket,服务端使用ServerSocket。通过Socket中的IO进行数据传输。
(2)客户端需要指明服务端接收端的Ip与端口号。服务端需要指明接受的端口号。
(3)接受的服务端可以得到客户端的ip
(4)通过Socket可以得到 InputStream和OutputStream
(5)先启动服务端,然后启动客户端
客户端发送,服务端接收:
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10003);
Socket s = ss.accept();//获得客户端的Socket
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int count = in.read(b);
String str = new String(b,0,count);
System.out.println(str);
//只关闭Socket和ServerSocket
s.close();
ss.close();
}
}
import java.io.OutputStream;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
//指明目的的ip和端口
Socket s = new Socket("127.0.0.1",10003);
OutputStream os = s.getOutputStream();
os.write("hello".getBytes());
//只关闭Socket
s.close();
}
}
客户端与服务端互相读写:
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10004);
Socket s = ss.accept();//获得客户端的Socket
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//读取
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int count = in.read(b);
String str = new String(b,0,count);
System.out.println("服务端接收的数据:"+str);
OutputStream out = s.getOutputStream();
out.write("这是服务端写的数据".getBytes());
//只关闭Socket和ServerSocket
s.close();
ss.close();
}
}
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
//指明目的的ip和端口
Socket s = new Socket("127.0.0.1",10004);
//写过去
OutputStream os = s.getOutputStream();
os.write("这是客户端写的数据".getBytes());
//进行读取
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int count = in.read(b);
String str = new String(b,0,count);
System.out.println("从服务端读到的数据:"+str);
//只关闭Socket
s.close();
}
}
使用Buffered提高效率,从键盘读取,客户端与服务端进行数据读写:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();//获得客户端的Socket
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//读取,从客户端读取
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//写,写入客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String str = null;
while((str = br.readLine())!= null){
bw.write(str.toUpperCase());
//注意:下面的两行一定要写,因为readLine没有换行符
bw.newLine();
bw.flush();
}
//不需要关闭流
//只关闭Socket和ServerSocket
s.close();
ss.close();
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
//指明目的的ip和端口
Socket s = new Socket("127.0.0.1",10005);
//从键盘读
BufferedReader brJian = new BufferedReader(new InputStreamReader(System.in));
//写过去,写到服务端去
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//读取,从服务端读取
BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = brJian.readLine())!=null){
//控制从键盘读取会结束的
if("over".equals(line)){
break;
}
bw.write(line);
//注意:下面的两行一定要写,因为readLine没有换行符
bw.newLine();
bw.flush();
//注意:从服务端读是写在这里的,写在了while中,实时通讯
String str = brFu.readLine();
System.out.println("客户端读到的数据:"+str);
}
//只关闭Socket
s.close();
//关闭键盘读取的流
brJian.close();
}
}
使用PrintWriter,优于Buffered:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();//获得客户端的Socket
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//读取,从客户端读取
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//写,写入客户端
//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter bw = new PrintWriter(s.getOutputStream());
String str = null;
while((str = br.readLine())!= null){
bw.println(str.toUpperCase());
bw.flush();//需要刷新
//也可以在创建PrintWriter的时候指明会自动刷新
}
//不需要关闭流
//只关闭Socket和ServerSocket
s.close();
ss.close();
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
//指明目的的ip和端口
Socket s = new Socket("127.0.0.1",10005);
//从键盘读
BufferedReader brJian = new BufferedReader(new InputStreamReader(System.in));
//写过去,写到服务端去
//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter bw = new PrintWriter(s.getOutputStream());
//读取,从服务端读取
BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = brJian.readLine())!=null){
//控制从键盘读取会结束的
if("over".equals(line)){
break;
}
bw.println(line);
bw.flush();
//注意:从服务端读是写在这里的,写在了while中,实时通讯
String str = brFu.readLine();
System.out.println("客户端读到的数据:"+str);
}
//只关闭Socket
s.close();
//关闭键盘读取的流
brJian.close();
}
}
上面程序可能存在的问题:客户端从键盘读,有结束的时候,写过去有结束的时候,但是服务端读没有结束的时候,就会造成阻塞。后面讲解决的办法。
文件复制(Buffered、PrintWriter):
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();//获得客户端的Socket
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//读取,从客户端读取
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//写,写入客户端
PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
//写入文件,文件不存在的时候会自动的创建
PrintWriter pw = new PrintWriter(new FileWriter("C:\\Users\\huer\\Desktop\\b.txt"),true);
String str = null;
while((str = br.readLine())!= null){
pw.println(str);
}
//这里需要写在循环的外面
bw.println("服务端说:上传成功");
//不需要关闭流
//只关闭Socket和ServerSocket
s.close();
ss.close();
pw.close();
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
//指明目的的ip和端口
Socket s = new Socket("127.0.0.1",10006);
//从文件读
BufferedReader brJian = new BufferedReader(new FileReader("C:\\Users\\huer\\Desktop\\a.txt"));
//写过去,写到服务端去
PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
//读取,从服务端读取
BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
//从文件读取
while((line = brJian.readLine())!=null){
bw.println(line);
}
//这个是写在循环外的
String str = brFu.readLine();
System.out.println("客户端读到的数据:"+str);
//只关闭Socket
s.close();
//关闭文件流
brJian.close();
}
}
读写都是对应着的。
分析存在的问题:客户端从文件读,有结束的时候,所以写到服务端有结束的时候,但是服务端还在一直等着接收客户端传过来的数据,会一直等着,不知道什么时候结束,所以服务端存在方法阻塞的情况。
shutdownOutput()方法解决方法阻塞:
客户端写结束的时候,指明结束写
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();//获得客户端的Socket
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//读取,从客户端读取
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//写,写入客户端
PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
//写入文件,文件不存在的时候会自动的创建
PrintWriter pw = new PrintWriter(new FileWriter("C:\\Users\\huer\\Desktop\\b.txt"),true);
String str = null;
while((str = br.readLine())!= null){
pw.println(str);
}
//这里需要写在循环的外面
bw.println("服务端说:上传成功");
//不需要关闭流
//只关闭Socket和ServerSocket
s.close();
ss.close();
pw.close();
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
//指明目的的ip和端口
Socket s = new Socket("127.0.0.1",10006);
//从文件读
BufferedReader brJian = new BufferedReader(new FileReader("C:\\Users\\huer\\Desktop\\a.txt"));
//写过去,写到服务端去
PrintWriter bw = new PrintWriter(s.getOutputStream(),true);
//读取,从服务端读取
BufferedReader brFu = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
//从文件读取
while((line = brJian.readLine())!=null){
bw.println(line);
}
s.shutdownOutput();//指明结束写
//这个是写在循环外的
String str = brFu.readLine();
System.out.println("客户端读到的数据:"+str);
//只关闭Socket
s.close();
//关闭文件流
brJian.close();
}
}
下面是一个解决方法阻塞的例子:
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10007);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
FileOutputStream fo = new FileOutputStream("C:\\Users\\huer\\Desktop\\图片\\2.jpg");
//从文件读,上传到另一个图片
byte[] b = new byte[1024];
int len = 0;
InputStream in = s.getInputStream();
while((len = in.read(b))!=-1){
fo.write(b, 0, len);
}
OutputStream oos = s.getOutputStream();
oos.write("上传成功".getBytes());
s.close();
ss.close();
fo.close();
}
}
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
Socket s = new Socket("127.0.0.1",10007);
//文件
FileInputStream fi = new FileInputStream("C:\\Users\\huer\\Desktop\\图片\\1.jpg");
OutputStream os = s.getOutputStream();
//从文件读,写过去
byte[] b = new byte[1024];
int len = 0;
while((len = fi.read(b))!=-1){
//读文件有结束的时候,所以写过去有结束的时候,但是服务端不知道,所以下面用shutdownOutput指明写入结束
os.write(b, 0, len);
}
s.shutdownOutput();//关闭输出流
//从服务端读,打印出来
InputStream in = s.getInputStream();
byte[] bin = new byte[1024];
int blen = 0;
blen = in.read(bin);
System.out.println(new String(bin,0,blen));
//关闭连接和文件流
s.close();
fi.close();
}
}
使用线程实现TCP传输:
思路:服务端的ServerSocket只能初始化一次,然后只要有一个客户端连接上来,就有一个Socket,就启动一个线程。
服务端ServerSocket不用关闭。
使用线程实现图片文件上传。客户端从本地文件一直读取图片并上传至服务端,服务端将读取到的图片保存起来。
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class PicServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10007);
//允许多个人连接进来,使用while
while(true){
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
//ss.close();//不用进行关闭
}
}
class PicThread implements Runnable{
private Socket s;
PicThread(Socket s){
this.s = s;
}
@Override
public void run() {
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try{
System.out.println(ip+"....connection");
//用File封装一下
//File f = new File("C:\\Users\\huer\\Desktop\\图片\\2.jpg");
File f = new File("C:\\Users\\huer\\Desktop\\图片\\"+ip+"("+count+")"+".jpg");
//这是避免文件名覆盖
if(f.exists()){
//这里使用的是++count,不要使用count++
f = new File("C:\\Users\\huer\\Desktop\\图片\\"+ip+"("+(++count)+")"+".jpg");
}
System.out.println(count);
FileOutputStream fo = new FileOutputStream(f);//不存在的时候会自动创建
//从文件读,上传到另一个图片
byte[] b = new byte[1024];
int len = 0;
InputStream in = s.getInputStream();
while((len = in.read(b))!=-1){
fo.write(b, 0, len);
}
OutputStream oos = s.getOutputStream();
oos.write("上传成功".getBytes());
s.close();
fo.close();
}catch(Exception e){
throw new RuntimeException(ip+"上传文件失败");
}
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
Socket s = new Socket("127.0.0.1",10007);
//关于图片的路径需要重新修改,现在先不管,测试的话是有问题的
if(args.length!=1){
System.out.println("请选择一个jpg格式的图片");
return;
}
File f = new File(args[0]);
if(!(f.exists() && f.isFile())){
System.out.println("该文件有问题,要么不存在,要么不是文件");
return;
}
if(!(f.getName().endsWith(".jpg"))){
System.out.println("图片格式错误,请重新选择");
return;
}
if(f.length()>1024*1024*5){
System.out.println("文件过大,重新选择");
return;
}
//文件
FileInputStream fi = new FileInputStream(f);
OutputStream os = s.getOutputStream();
//从文件读,写过去
byte[] b = new byte[1024];
int len = 0;
while((len = fi.read(b))!=-1){
os.write(b, 0, len);
}
s.shutdownOutput();//关闭输出流
//从服务端读,打印出来
InputStream in = s.getInputStream();
byte[] bin = new byte[1024];
int blen = 0;
blen = in.read(bin);
System.out.println(new String(bin,0,blen));
//关闭连接和文件流
s.close();
fi.close();
}
}
用户登录次数限制:
思路:用户最多进行三次的尝试登陆,服务端也只进行三次的测试登陆,所以有一个for循环。for循环有结束控制的条件,所以不需要使用shutdownOutput()
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class PicServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(10008);
while(true){
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
}
}
class PicThread implements Runnable{
private Socket s;
PicThread(Socket s){
this.s = s;
}
@Override
public void run() {
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try{
System.out.println(ip+"....connection");
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
for(int i=1;i<=3;i++){
//这里是非常要注意的点:在循环里面,每次都要重新的打开用户名的文件,操作完一次之后就要进行关闭
//所以brFile的创建要在for中,brFile的关闭也要在for中
BufferedReader brFile = new BufferedReader(new FileReader("C:\\Users\\huer\\Desktop\\user.txt"));
String name = br.readLine();
if(name == null){
break;
}
System.out.println(name);
boolean f = false;
String line = null;
while((line =brFile.readLine())!=null){
System.out.println("服务端从文件中读到的数据:"+line);
if(line.equals(name)){
f = true;
break;
}
}
if(f){
System.out.println(name+"已登陆");
pw.println(name+"欢迎登陆");
break;//停止服务端的for循环
}else{
System.out.println(name+"尝试登陆");
pw.println(name+"用户名不存在");
}
brFile.close();
}
s.close();
}catch(Exception e){
throw new RuntimeException(ip+"校验失败");
}
}
}
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
//客户端
public class TcpClient {
public static void main(String[] args) throws Exception{
Socket s = new Socket("127.0.0.1",10008);
BufferedReader brJian = new BufferedReader(new InputStreamReader(System.in));//从键盘读
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//从服务端读
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//向服务端写
//只允许用户操作3次
for(int i=1;i<=3;i++){
String line = brJian.readLine();
//防止方法 的阻塞
if(line == null){
break;
}
pw.println(line);
String str = br.readLine();
System.out.println("从服务端读取的信息:"+str);
//登陆成功之后就退出循环
if(str.contains("欢迎")){
break;//如果读到欢迎登陆了,客户端就停止for循环
}
}
s.close();
brJian.close();
}
}
浏览器-自定义服务端,访问的时候:192.168.159.10:11000,注意ip不要写loacalhost,不要写127.0.0.1:
服务端:
public class ServerDemo {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(11000);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//这里就是简单的测试
//客户端连接上服务端之后,发送给客户端,"客户端你好"
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
//pw.println("<font color='red' size='7'>客户端,你好</font>");
pw.println("客户端,你好");
s.close();
ss.close();
}
}
浏览器-自定义服务端,服务端读取浏览器传递过来的消息头,然后给浏览器写过去一些数据:
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(11000);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//输出一下从浏览器读过来的信息头
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int len = 0;
len = in.read(b);
String str = new String(b,0,len);
System.out.println("从浏览器读到的数据:"+str);
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("<font color='red' size='7'>客户端,你好</font>");
//pw.println("客户端,你好");
s.close();
ss.close();
}
}
从浏览器读到的数据:GET / HTTP/1.1
Host: 192.168.159.10:11000(这里就相当于客户端的Socket)
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,en-US;q=0.8,zh;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
自定义浏览器-自定义服务器,就是客户端写过去的数据首先写头消息,然后读服务端返回的数据:
自定义浏览器就是:写过去头消息,然后是数据:
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
//自定义服务器
public class ServerDemo {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(11000);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connection");
//输出一下从浏览器读过来的信息头
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int len = 0;
len = in.read(b);
String str = new String(b,0,len);
System.out.println("从浏览器读到的数据:"+str);
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("<font color='red' size='7'>客户端,你好</font>");
//pw.println("客户端,你好");
s.close();
ss.close();
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
//自定义浏览器
public class MyIE {
public static void main(String[] args) throws Exception{
Socket s = new Socket("192.168.159.10",11000);
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("GET / HTTP/1.1");//"/"是请求的路径
pw.println("Accept: */*");
pw.println("Accept-Language: zh-CN");
pw.println("Host: 192.168.159.10:11000");
pw.println("Connection: keep-alive");
pw.println("Connection: closed");
//下面的两行是固定的格式
pw.println();
pw.println();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
line=br.readLine();
System.out.println(line);
s.close();
}
}
URL
封装浏览器访问的url,表示统一资源定位符。
public static void main(String[] args) throws Exception {
URL url = new URL("http://192.168.159.10:11000/myweb/test.html?name=zhangsan&age=20");
System.out.println(url.getProtocol());//http
System.out.println(url.getHost());//192.168.159.10
if(url.getPort() == -1){
String port = "11000";
}
System.out.println(url.getPort());//11000
System.out.println(url.getPath());// /myweb/test.html
System.out.println(url.getFile());// /myweb/test.html?name=zhangsan&age=20
System.out.println(url.getQuery());// name=zhangsan&age=20
}
URLConnection
URLConnection表示URL所引用的远程对象的连接。url.openConnection()。每次调用这个方法都会得到一个新的连接。
public static void main(String[] args) throws Exception {
URL url = new URL("http://192.168.159.10:11000/myweb/test.html");
URLConnection connection = url.openConnection();
System.out.println(connection);
InputStream in = connection.getInputStream();
OutputStream out = connection.getOutputStream();
//进行读写.....
}