黑马程序员--网络编程

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

注:视频来源,毕向东老师的 JAVA 基础视频。

一、网络编程的基本组成部分

1、网络模型

–>OSI参考模型

–>TCP/IP参考模型

2、网络通讯要素

2.1 IP地址

–>–>网络中设备的标识

–>–>不易记忆,可用主机名

–>–>本地回环地址:127.0.0.1主机名:localhost

2.2 端口号

–>–>用于标识进程的逻辑地址,不同进程的标识

–>–>有效端口:0~65535,其中0~1024为系统使用或保留端口。

2.3 传输协议

–>–>通讯的规则

–>–>常见协议:TCP,UDP

数据通信的原理:就是数据传输的过程。

参考模型图示:
这里写图片描述
不同主机间的通信,数据包的封包与拆包:
这里写图片描述

二、TCP和UDP的特点

1) UDP:

1、将数据及源和目的封装成数据包中,不需要建立连接。

2、每个数据报的大小限制在64k。

3、因为是无连接,是不可靠的协议。

4、不需要建立连接,传输速度快。

2) TCP:

1、建立连接,形成传输数据的通道。

2、在连接中进行大数据量传输。

3、通过三次握手完成连接,是可靠协议。

4、必须建立连接,效率会稍低。

3) 认识 Socekt :(翻译为:插座)

Socket 就是为网络服务提供的一种机制。

1、通信的两端都是 Socket 。

2、网络通信其实就是 Socket 间的通信。

3、数据在两个 Socket 间通过 IO 传输

三、UDP 传输:(特有传输方式)

DatagramSocket:此类表示用来发送和接受数据报包的套接字。特点:既能发送,又能接收。

DatagramPacket:此类表示数据报包。数据报包用来实现无连接包投递服务。

3.1、UDP 的传输步骤:

1、建立发送端,接收端。

2、建立数据包。

3、调用 Socket 的发送接收方法。

4、关闭 Socket 。

总结:发送端与接收端是两个独立运行的程序。

练习:

package fuxi3;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 需求:利用Udp传输建立一个聊天工具。
 *@author XiaLei
 */
public class Day23Test1 {

    public static void main(String[] args) throws SocketException {
        //创建服务。通过DatagramSocket对象  
        DatagramSocket send = new DatagramSocket();
        //创建udp Socket服务,建立端点  
        DatagramSocket rece = new DatagramSocket(10000);
        //建立两个线程,分别发送和接受数据。
        new Thread(new Send(send)).start();
        new Thread(new Rece(rece)).start();
    }

}
class Send implements Runnable{

    private DatagramSocket ds;
    Send(DatagramSocket ds){
        this.ds = ds;
    }
    public void run() {
        BufferedReader bufr = null;
        try{
            bufr = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            while((line = bufr.readLine())!=null){
                //确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
                byte[] buf = line.getBytes();
                DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10000);
                ds.send(dp);//通过Socket服务,将已有的数据包发送出去。通过send方法。  
            }
        }
        catch(Exception e){
            throw new RuntimeException("发送失败");
        }
    }   
}
class Rece implements Runnable{
    private DatagramSocket ds;
    Rece(DatagramSocket ds){
        this.ds = ds;
    }
    public void run() {
        try{
            //一直处于接收状态  
            while(true){
                //定义数据包。用于存储数据 
                byte[] buf = new byte[1024];
                //通过Socket服务的receive方法将接收到的数据存入数据包中
                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("接受失败");
        }
    }
}

四、TCP 传输:Socket 和 ServetSocket

TCP 传输的基本步骤:

1、建立客户端和服务器端

2、建立连接后通过 Socket 中的 IO 流进行数据传输

3、关闭 Socket

总结:同样,客户端和服务器端是两个独立的应用程序。

4.1、演示 tcp 传输。

1、tcp 分客户端和服务器端。

2、客户端对应的对象是 Socket。

3、服务器端对应的对象是 ServetSocekt。

客户端code:

package fuxi3;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 需求:建立一个文本转换服务器。
 * 客户端不断发送文本数据,服务端接受数据,并将数据转换为大写返回。
 * 当客户端输入“over”,转换结束。
 *@author XiaLei
 */
public class TcpClient {

    public static void main(String[] args) throws Exception {
         //创建客户端的 Socket 服务,指定目的主机和端口 
        Socket s = new Socket("127.0.0.1",10001);
        //建立缓冲区,将键盘录入存入缓冲区
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        //创建打印流对象加载进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){
            if("over".equals(line))
                break;
            out.println(line);//将键盘录入信息载入Socket输出流
            String len = bufin.readLine();//读取Socket输入流信息并打印到控制台
            System.out.println("client"+len);                   
        }
        //关流
        bufr.close();
        //关客户端
        s.close();
    }

}

服务端code:

package fuxi3;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 *@author XiaLei
 */
public class TcpSever {

    public static void main(String[] args) throws Exception {
         //建立服务端的 Socket 服务。并监听一个端口。
        ServerSocket ss = new ServerSocket(10001);
         //通过 accept 方法获取连接过来的客户端对象。
        Socket s = ss.accept();
        //获取ip 
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+".....connect");
          //获取客户端发送过来的数据,那么要使用客户端的读取流方法  
        BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //将读取的字符串改为大写发送回客户端
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);
        String line = null;
        while((line = bufin.readLine())!=null){
            System.out.println("server"+line);
            out.println(line.toUpperCase());
        }
        //关闭客户端,必须关闭客户端 
        s.close();
        ss.close();
    }

}

4.2、练习:利用Tcp传输,上传图片
客户端code:

package fuxi3;



import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 
 *@author XiaLei
 */
public class TcpClientPic {

    public static void main(String[] args) throws Exception {

        Socket s = new Socket("127.1.1.0",10002);
        OutputStream out = s.getOutputStream();
        FileInputStream fis = new FileInputStream("D:\\1.jpg");
        byte[] buf = new byte[1024];
        int len = 0;
        while((len = fis.read(buf))!=-1){
            out.write(buf,0,len);
        }
        s.shutdownOutput();//设定结束标记,因为服务器端一直在读数据,它不知道什么时候停止。
        BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String line = bufr.readLine();
        System.out.println(line);
        fis.close();
        s.close();
    }

}

服务端code:

package fuxi3;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 *@author XiaLei
 */
public class TcpServerPic {

    public static void main(String[] args) throws Exception {

        ServerSocket ss = new ServerSocket(10002);
        Socket s = ss.accept();
        System.out.println(s.getInetAddress().getHostAddress()+"....connect");

        InputStream in = s.getInputStream();
        FileOutputStream fos = new FileOutputStream("D:\\2.jpg");
        byte[] buf = new byte[1024];
        int len = 0;
        while((len = in.read(buf))!=-1){
            fos.write(buf,0,len);
        }
        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        bufw.write("服务器接受成功");
        bufw.flush();//建立缓冲区一定要记得刷新,不刷新客户端接受不到数据,打印null。
        fos.close();
        s.close();
        ss.close();
    }

}

第五部分 综合应用

1、多并发上传图片文件

建立PicClient and PicServer

1.1 客户端

需求:上传图片

实现的基本步骤:

1、建立服务端点。

2、读取客户端已有的图片数据。

3、通过 Socket 输出流将数据发给服务端。

4、读取服务端反馈信息。

5、关闭。

code:

package 并发传图片;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 
 *@author lenovo
 */
public class Client {

    public static void main(String[] args) throws Exception{

        if(args.length!=1){  
            System.out.println("请选择一个jpg格式的图片文件");  
        }  
        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("192.168.0.100",10010);

        FileInputStream fis=new FileInputStream(file);

        OutputStream out=s.getOutputStream();

        byte[] buf=new byte[1024];

        int len=0;

        while ((len=fis.read(buf))!=-1){
            out.write(buf,0,len);
        }
         //创建结束标记  
        s.shutdownOutput();
         //获取服务器端发回来的接收进度信息 
        InputStream in=s.getInputStream();
        byte[] b=new byte[100];
        int x=0;
        while ((x=in.read(b))!=-1){
            System.out.println(new String(b,0,x));
        }
        fis.close();
        s.close();
        }   
}

1.2 服务器端
1、服务端服务,并监听窗口
2、获取客户端对象,并获取客户ip
3、读取客户端输入流数据
4、写入文件
5、用客户端输出流反馈信息
6、关流
注意:
为了让多个客户端同时并发访问服务端。服务端最好是将每个客户端请求封装到一个单独的线程中,这样就可以同时处理多个客户端的请求了。

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

服务器端code:

package 并发传图片;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;

/**
 * 
 *@author lenovo
 */
 class PicServer implements Runnable {
        private Socket s;
        PicServer(Socket s){
            this.s=s;
        }
        public void run(){
            int count=1;
            String ip=s.getInetAddress().getHostAddress();
            try {
                System.out.println(ip+"...connect");
                //通过客户端的读取流读取数据  
                InputStream ins=s.getInputStream();
                File file=new File(ip+"("+count+")"+".jpg");
                //判断文件是否存在
                if (file.exists())
                    file=new File(ip+"("+(count++)+")"+".jpg");
                 //将数据写入到指定文件中  
                FileOutputStream fos=new FileOutputStream(file);

                byte[] buf=new byte[1024];
                int len=0;
                while ((len=ins.read(buf))!=-1){
                    fos.write(buf,0,len);
                    fos.close();
                    s.close();
                }
                //将收到图片数据的信息返回给客户端  
                OutputStream outs=s.getOutputStream();
                outs.write("上传成功".getBytes());
                }
            catch(Exception e){
                throw new RuntimeException("上传失败");
            }
        }
}
 class Server {
    public static void main(String[] args)throws Exception{
        ServerSocket ss=new ServerSocket(10010);
        while (true){
            //获取客户端对象  
            Socket s=ss.accept();
             //客户端执行线程  
            new Thread(new PicServer(s)).start();
        }
    }
}

2、客户端并发登录
客户端通过键盘录入用户名,服务端对这个用户名进行校验。
如果该用户存在,在服务端显示xxx,已登陆;并在客户端显示xxx,欢迎光临。
如果用户不存在,在服务端显示xxx,尝试登陆;并在客户端显示xxx,该用户不存在。
最多就登录三次。
客户端code:

package 客户端并发登录;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 
 *@author lenovo
 */
public class Client {

    public static void main(String[] args) throws Exception{
        Socket s=new Socket("127.0.0.1",10100);

        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

        PrintWriter out=new PrintWriter(s.getOutputStream(),true);

        BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));


        for (int x=0;x<3;x++){

            String line=bufr.readLine();//读取键盘录入
                if(line==null)
                    break;
            out.println(line);

            String info=bufIn.readLine();
            if (info.contains("欢迎"))//如果登录成功,就跳出循环  
                break;

        }
        bufr.close();
        s.close();  
    }
}

服务器端code:

package 客户端并发登录;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 *@author lenovo
 */
public class Server {

    public static void main(String[] args) throws Exception{
        ServerSocket ss=new ServerSocket(10100);

        while (true){
            Socket s=ss.accept();
            //客户端执行线程 
            new Thread(new DenLu(s)).start();   
        }
    }
}
class DenLu implements Runnable{

    private Socket s;

    DenLu(Socket s){
        this.s=s;
    }
    public void run (){

        System.out.println(s.getInetAddress().getHostAddress()+"...connected");
        try{

                for (int x=0;x<3;x++){
                //读取数据库中的数据,这里用文件来表示数据库    
                BufferedReader bufr=new BufferedReader(new FileReader("D:\\username.txt"));
                //通过客户端的读取流读取数据  
                BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));

                PrintWriter out=new PrintWriter(s.getOutputStream(),true);

                String name=bufIn.readLine();
                if (name==null)
                    break;
                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+"登录失败");
                            }                           
                    bufr.close();
                    s.close();  
            }   
        }
        catch(Exception e){
            throw new  RuntimeException(s.getInetAddress().getHostAddress()+"校验失败");
        }       
    }   
}

第六部分 DNS 域名解析服务器
图解:
这里写图片描述
1、地址栏访问主机的时候,首先是先访问本机系统内的 C–>System32–>

Drivers–>hosts文件

2、常见问题:禁止软件更新的方法(通常软件更新,会带来收费的问题)

到 hosts 文件夹中,把软件更新的地址,如:www.myeclipse.com 加入到列表中。

例子:127.0.0.1 www.myeclipse.com

3、那么,当软件要更新访问的地址就会变成本机地址,所以就会访问失败,所以软件更新失败 。就好比杀毒软件。发现一些垃圾网站,就往 hosts 文件中加入这个网站来屏蔽。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值