黑马程序员——java基础知识之网络编程(二)

时间:2023-02-18 21:49:49

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
(一)网络编程的深入
1、基础知识总结:
①网络编程:主要是和IO流联系紧密,基本上有网络编程的地方,就有IO流的应用。
②当网络编程遇到一对多传输时,要利用多线程来处理
③小知识点:
游览器输入网址进行访问的时候,会先在本地的hosts文件(c:\windows\system32\drivers\ext\host)中找对应的映射。若有,则直接返回请求;若无,则到公网的映射列表即DNS中找对应的映射,找到后,将主机名对应的IP地址返回给本机,本机通过这个IP地址找到对应的服务器。
④网络编程主要要掌握UDP传输和TCP传输
UDP传输的步骤:
1)创建 UDPSocket发送服务对象:
DatagramSocket(),不指定端口。DatagramSocket(int port),指定端口。
2)发送:void send(DatagramPacket p)
3)接收:void receive(DatagramPacket p)
TCP传输的步骤:
客户端:
1)创建Socket服务,并指定要连接的主机端口。通路一建立,就会产生Socket流(包括输入流和输出流),通过方法获取
2)为了发送数据,应获取Socket中的输出流,如果要接收服务端的反馈信息,还需要获取Socket的输入流
3)通过输出流的write()方法将要发送的数据写入到流中
4)关闭Socket流资源
服务端:
1)建立服务端的Socket服务,并监听一个端口。通过ServerSocet带端口参数的构造函数
2)获取连接过来的客户对象,通过ServerSocket的accept()方法,此方法是阻塞式的,如果服务端没有连接到就会一直等待
3)客户端如果发过来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过来的数据,并输出到指定目的地。
4)关闭服务端(可选)。一般服务端是常开的,因为在实际应用中,随时有客户端在请求连接和服务。但这里需要定时关闭客户端对象流,避免某一个客户端长时间占用服务器端。

2、网络编程的综合应用
例子1:利用网络编程实现图片上传

package cn.dhj;

import java.io.*;
import java.net.*;

/*
* 需求:网络上传图片
*客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。
*/


public class UploadPic {
public static void main (String[] args) throws Exception{
Socket s = new Socket("127.0.0.1",8888);
FileInputStream fis = new FileInputStream("c:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[2014];
int len = 0;
if((len=fis.read(buf))!=-1){
out.write(buf , 0 ,len);
}
s.shutdownOutput();//告诉服务端数据已经写完,也就是做一个标记
InputStream In = s.getInputStream();
byte[] bufIn = new byte[2014];
int read = In.read(bufIn);
System.out.println(new String(bufIn,0,read));
}
}
class UploadPicServer {
public static void main (String[] args) throws Exception{
ServerSocket ss = new ServerSocket(8888);
Socket s =ss.accept();
InputStream Inc = s.getInputStream();
FileOutputStream outc = new FileOutputStream("server.bmp");
byte[] buf = new byte[2014];
int len = 0;
while((len=Inc.read(buf))!=-1){
outc.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
Inc.close();
ss.close();
s.close();
}
}

例子2、网络编程(TCP-客户端并发上传图片)

package cn.dhj;

import java.io.*;
import java.net.*;

/*
* /*
服务端
那么为了可以让多个客户端同时并发访问服务端。
那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。

如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。
*/

public class TCPserver {
public static void main (String[] args) throws Exception{
ServerSocket ss = new ServerSocket(8888);
while(true){
Socket s = ss.accept();
//启动新线程
new Thread(new PicThrowd(s)).start();
}
}

}

class PicThrowd implements Runnable{
private Socket s;

public PicThrowd(Socket s) {
super();
this.s = s;
}

public void run(){
String ip = s.getInetAddress().getHostAddress();
int count = 1;
try{
System.out.println(ip+"......connected");
InputStream Inc = s.getInputStream();
File dir = new File("d:\\pic");
File file = new File(dir,ip+"("+count+")"+".jpg");
FileOutputStream outc = new FileOutputStream(file);
byte[] buf = new byte[2014];
int len = 0;
while((len=Inc.read(buf))!=-1){
outc.write(buf,0,len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
Inc.close();
outc.close();
s.close();
}catch(Exception e){
throw new RuntimeException(ip+"上传失败");
}
}
}


/*
客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。
*/

class TCPclient{
public static void main(String[] args) throws Exception{
//对上传的图片首先进行判断
if(args.length!=1)
{
System.out.println("请选择一个jpg格式的图片");
return ;
}
File file = new File(args[0]);
if(!(file.exists() && file.isFile()))
{
System.out.println("该文件有问题,要么补存在,要么不是文件");
return ;
}
if(!file.getName().endsWith(".jpg"))
{
System.out.println("图片格式错误,请重新选择");
return ;
}

if(file.length()>1024*1024*5)
{
System.out.println("文件过大,没安好心");
return ;
}
Socket s = new Socket("127.0.0.1",8888);
FileInputStream fIn = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[2014];
int line = 0;
while((line = fIn.read(buf))!=-1){
out.write(buf, 0, line);
}
//告诉服务器已经写完了
s.shutdownInput();
//接受服务器发送的信息
InputStream Inp = s.getInputStream();
byte[] bufin = new byte[2014];
int sum = Inp.read(bufin);
System.out.println(new String(bufin,0,sum));
fIn.close();
s.close();
}
}

例子3:TCP客户端并发登陆

package cn.dhj;
/*
客户端通过键盘录入用户名。
服务端对这个用户名进行校验。

如果该用户存在,在服务端显示xxx,已登陆。
并在客户端显示 xxx,欢迎光临。

如果该用户存在,在服务端显示xxx,尝试登陆。
并在客户端显示 xxx,该用户不存在。

最多就登录三次。
*/

import java.io.*;
import java.net.*;
//客户端
public class UerserLoderClient{
public static void main (String[] args) throws Exception{
Socket s = new Socket("127.0.0.1",8888);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
BufferedReader bout = new BufferedReader(new InputStreamReader(s.getInputStream()));

for (int i=1;i<=3;i++){
String line = bufr.readLine();
if (line == null)
break;
out.write(line);
String info = bout.readLine();
System.out.println("info"+info);
if(info.contains("欢迎"))
break;
}
}
}
//服务端
class UererLoaderServer{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(8888);
while(true){
Socket s = ss.accept();
new Thread(new ThreadServer(s)).start();
}
}
}
//利用多线程实现并发登录
class ThreadServer implements Runnable{
private Socket s;
public ThreadServer(Socket s) {
super();
this.s = s;
}
public void run(){
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");
try{
for(int i=1;i<=3;i++){
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String name = bufIn.readLine();
if(name==null)
break;
BufferedReader bufr = new BufferedReader(new FileReader("user.text"));
PrintWriter out = new PrintWriter(s.getOutputStream());
String line = null;
boolean flag = false;
while((line=bufr.readLine())!=null){
if(line.equals(name)){
flag = true;
break;
}

}
if(flag = true){
System.out.println(name+"已登入");
out.write(name+"欢迎登入");
}else{
System.out.println(name+"尝试登入");
out.write(name+"用户名不存在");
}
s.close();

}
}catch(Exception e){
throw new RuntimeException(ip+"校验失败");
}
}

}

例子4、客户端和游览器的演示
总结:游览器是一个客户端
java编译是在传输层和网际层处理的,会接受到全部的消息,包含了头消息。而浏览器处于应用层,已将发送来的头消息去除,只留下了主体信息。

import java.io.*;  
import java.net.*;

//服务器
class ServerDemo
{
public static void main(String[] args)throws Exception
{
//创建服务,监听端口
ServerSocket ss=new ServerSocket(10000);
//获取客户端
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));
//返回信息写入客户端输出流
PrintWriter out=new PrintWriter(s.getOutputStream(),true);///true一定要记得写

out.println("<font color='red' size='7'>客户端你好!</font>");

s.close();//关流
ss.close();
}
}

例子5、
自定义浏览器,显示网页信息

/* 
自定义浏览器,显示网页信息
*/


import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;

class MyIEGUIDemo
{
//定义所需组件引用
private Frame f;
private Button but,bok;
private TextField tf;
private TextArea ta;

//构造函数
MyIEGUIDemo()
{
init();
}

//窗体基本设置于功能实现
public void init()
{
//组件实例化
f=new Frame("我的Window");
but=new Button("跳转");
tf=new TextField(50);
ta=new TextArea(25,60);

//基本设置
f.setBounds(300,150,500,500);
f.setLayout(new FlowLayout());

//添加组件
f.add(tf);
f.add(but);
f.add(ta);

//窗体事件
myEvent();

//窗体显示
f.setVisible(true);
}

//注册事件
public void myEvent()
{
//窗体关闭功能
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});

//“跳转”按钮事件
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
showFile();//显示网页内容在文本区中
}
});



//文本框键盘事件
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
//如果键盘按下Enter键,就将网页内容显示在文本区中
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showFile();
}
});
}

//显示网页内容
private void showFile()
{
ta.setText("");
String path=tf.getText();//获取输入的路径
try
{
//封装地址对象
URL url =new URL(path);
连接网页服务器
URLConnection conn=url.openConnection();
//读取流,用于读取服务器返回数据
InputStream in=conn.getInputStream();

byte[] buf=new byte[1024*1024];

int len=in.read(buf);
//将数据显示在文本区中
ta.append(new String(buf,0,len));
}
catch (Exception e)
{
throw new RuntimeException("连接"+path+"网站失败");
}
}

public static void main(String[] args)
{
//运行窗体
new MyIEGUIDemo();
}
}

自定义游览器知识储备和总结:
了解URL和URLConnection:
1、URL:
URI:范围更大,条形码也包含于此范围
URL:范围较小,即域名
方法:
1)构造函数:URL(String protocol,String host,int port,String file);//根据指定 protocol、host、port号和 file 创建 URL对象。
2)String getProtocol();//获取协议名称
3)String getHost();//获取主机名
4)int getPort();//获取端口号
5)String getFile();//获取URL文件名
6)String getPath();//获取此URL的路径部分
7)String getQuery();//获取此URL的查询部,客户端传输的特定
2、URLConnection
方法:
1)URLConnection openConnection();//用URL调用此方法,返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。
2)InputStream getInputStream();//获取输入流
3)OutputStream getOutputStream();//获取输出流