【黑马程序员】网络编程——Java复习笔记

来源:互联网 发布:java中printf格式化输 编辑:程序博客网 时间:2024/05/20 08:25

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

网络编程

什么是网络编程?

用Java语言实现计算机间数据的信息传递和资源共享

网络编程的三要素

  1. IP地址:网络中计算机的唯一标识
    a:点分十进制 xxx.xxx.xxx.xxx
    b:IP地址的组成 网络号段+主机号段
    c:InetAddress类 是个没有构造方法的类 用于获取ip等
  2. 端口
    是应用程序的标识。范围:0-65535。其中0-1024不用。
  3. 协议
    UDP:数据打包,每一次不超过64k,不建立连接,效率高,不可靠
    TCP:建立数据通道,无限制,效率稍低,可靠

Socket机制

  1. 通信两端都应该有Socket对象
  2. 所有的通信都是通过Socket间的IO进行操作的. 网络通信其实就是Socket通信
    Socket套接字:网络上具有唯一标识的IP地址和端口号组合在一起构成唯一能识别的标识符套接字

UDP协议发送和接收数据

发送:

import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;/** * Created by mo on 15/11/21. * UDP发送数据 *  创建Socket对象 *  创建数据包 *  发送数据包 *  释放资源 */public class UDPsend {    public static void main(String[] args) throws IOException {        DatagramSocket datagramSocket = new DatagramSocket();        byte[] arr = "Hello,UDP,我来了".getBytes();//        InetAddress address = InetAddress.getByName("192.168.0.100");//接收端ip//        int port = 10765;//接收端端口//        DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length,address,port);        //精简版        DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length,InetAddress.getByName("192.168.0.100"),10765);        datagramSocket.send(datagramPacket);        datagramSocket.close();    }}

接收:

import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;/** * Created by mo on 15/11/21. * UDP接收数据 * *  创建接收端Socket对象 *  创建数据包(接收数据) *  调用Socket对象的接收方法 *  解包并显示在控制台 *  释放资源 */public class UDPreceive {    public static void main(String[] args)throws IOException{        //接收数据要指定端口        DatagramSocket datagramSocket = new DatagramSocket(10765);        //创建数据包接收        byte[] arr = new byte[1024];        DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length);        //接收数据        datagramSocket.receive(datagramPacket);        //解析数据内容//        int len = datagramPacket.getLength(); //获取数据实际长度//        byte[] received = datagramPacket.getData();//获取数据缓冲区        String s = new String(datagramPacket.getData(),0,datagramPacket.getLength());        //获取对方ip        String ip = datagramPacket.getAddress().getHostAddress();        System.out.println(ip+":"+s);        datagramSocket.close();    }}

案例1:键盘录入数据 直到录入886 客户端结束输入数据

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;/** * Created by mo on 15/11/21. * 需求:键盘录入数据 直到录入886 客户端结束输入数据 */public class Send {    public static void main(String[] args)throws IOException {        //这是发送端        System.out.println("请输入要发送的数据");        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        String line ;        //创建UDP用的DatagramSocket对象        DatagramSocket datagramSocket = new DatagramSocket();        //读取键盘录入的数据        while ((line = br.readLine())!=null){            if (line.equals("886")){                break;//如果是886则退出循环            }            //不是886,则创建数据包并把数据和接受者的端口+ip封装            byte[] arr = line.getBytes();            DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length, InetAddress.getByName("192.168.0.100"),10765);            //发送数据包            datagramSocket.send(datagramPacket);        }        datagramSocket.close();    }}/** * Created by mo on 15/11/21. * 这是接收端 */public class Received {    public static void main(String[] args) throws IOException{        //创建接收端DatagramSocket对象,传入端口号        DatagramSocket datagramSocket = new DatagramSocket(10765);        //循环接收数据        while (true){            byte[] arr = new byte[1024];            DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length);            datagramSocket.receive(datagramPacket);            String s = new String(datagramPacket.getData(),0,datagramPacket.getLength());            String ip = datagramPacket.getAddress().getHostAddress();            System.out.println(ip+":"+s);        }        //接收端应该一直开着 等待接收数据 所以不close    }}

案例2:多线程实现接收发送在同一窗口

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;/** * Created by mo on 15/11/21. * 多线程实现接收发送在同一窗口 */public class SendAndReceived {    public static void main(String[] args) throws SocketException {        //创建接收和发送的Socket对象        DatagramSocket sendSocket = new DatagramSocket();        DatagramSocket receiveSocket = new DatagramSocket(10765);        //创建和启动线程        Thread send = new Thread(new SendThread(sendSocket));        Thread receive = new Thread(new ReceiveThread(receiveSocket));        send.start();        receive.start();    }}/** * 这是发送线程类 */class SendThread implements Runnable{    //构造方法接收socket对象    private DatagramSocket datagramSocket;    public SendThread(DatagramSocket datagramSocket) {        this.datagramSocket = datagramSocket;    }    @Override    public void run() {        //键盘录入数据        System.out.println("请输入要发送的数据");        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        String line ;        try {            while ((line = br.readLine())!=null){                //如果输入的是886则退出循环                if (line.equals("886")){                    break;                }                //将输入的数据转为字节数组,然后封装到数据包并发送                byte[] arr = line.getBytes();                DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length, InetAddress.getByName("192.168.0.100"),10765);                datagramSocket.send(datagramPacket);            }        } catch (IOException e) {            e.printStackTrace();        }        datagramSocket.close();    }}/** * 这是接收线程类 */class ReceiveThread implements Runnable{    private DatagramSocket datagramSocket;    public ReceiveThread(DatagramSocket datagramSocket) {        this.datagramSocket = datagramSocket;    }    @Override    public void run() {        while (true){            byte[] arr = new byte[1024];            //创建接收用的数据包            DatagramPacket datagramPacket = new DatagramPacket(arr,arr.length);            //接收数据包            try {                datagramSocket.receive(datagramPacket);            } catch (IOException e) {                e.printStackTrace();            }            //解析数据包            String s = new String(datagramPacket.getData(),0,datagramPacket.getLength());            //获取发送者的ip            String ip = datagramPacket.getAddress().getHostAddress();            System.out.println(ip+":"+s);        }    }}

TCP协议发送和接收数据

发送:

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;/** * Created by mo on 15/11/21. * * TCP发送数据 *  创建发送端的Socket *      如果创建成功  就说明连接已建立 *  获取输出流写数据 *  释放资源 */public class ClientDemo {    public static void main(String[] args) throws IOException{//        Socket socket = new Socket(InetAddress.getByName("192.168.0.100",10888)); //太复杂了,简化一下        Socket socket = new Socket("192.168.0.100",10888);        OutputStream os = socket.getOutputStream();        os.write("hello,TCP,我来了".getBytes());        //客户端接收服务器端的反馈        InputStream is = socket.getInputStream();        byte[] arr = new byte[1024];        int len = is.read(arr);        String s = new String(arr,0,len);        System.out.println(s);        //关闭Socket        socket.close();    }}

接收:

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;/** * Created by mo on 15/11/21. * * TCP接收数据 * 创建接收端的ServerSocket * 监听客户端,返回一个对应的Socket对象 * 获取输入流,读取数据并显示 * 释放资源 */public class ServerDemo {    public static void main(String[] args) throws IOException {        ServerSocket ss = new ServerSocket(10888);        //监听,并接收到此套接字的连接,此方法在连接传入前一直阻塞        Socket s = ss.accept();        //获取数据        InputStream is = s.getInputStream();        byte[] arr = new byte[1024];        int len = is.read(arr);//阻塞式方法        String str = new String(arr, 0, len);        System.out.println(s.getInetAddress().getHostAddress() + ":" + str);        //服务器向客户端发送反馈,上面的read是阻塞式,所以不用担心上面还没执行完就执行下面        OutputStream os = s.getOutputStream();        os.write("服务器已收到信息".getBytes());        //关闭客户端的Socket        s.close();//        ss.close();//服务器要保持开启 不能关    }}

案例1:客户端键盘录入,服务器输出到控制台
客户端

import java.io.*;import java.net.Socket;/** * Created by mo on 15/11/21. */public class Client {    public static void main(String[] args) throws IOException {        Socket socket = new Socket("192.168.0.100", 10588);        //创建线程用于接收服务端发来的反馈        Thread rec = new Thread(new Receive(socket));        rec.start();        //键盘录入        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));        //把通道内的流给包装一下.因为Socket走的是字节流OutputStream        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));        String line;        while ((line = bf.readLine()) != null) {            if (line.equals("886")){                break;            }            bw.write(line);            bw.newLine();            bw.flush();        }        //这里也可以采用字节流,但要保证发送端接收端都用的字节流(具体代码为以下注释部分)//        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));//        OutputStream bw = socket.getOutputStream();////        String line;////        while ((line = bf.readLine()) != null) {//            if (line.equals("886")){//                break;//            }//            bw.write(line.getBytes());////        }        //关闭Socket        rec.interrupt();        socket.close();    }}/** * 这是用于接收服务器端发来的反馈的线程类 */class Receive implements Runnable{    //构造方法接收Socket对象    private Socket socket ;    public Receive(Socket socket) {        this.socket = socket;    }    @Override    public void run() {        while (true){            //判断Socket连接是否被关闭            if (socket.isClosed()){                break;            }            //连接还存在就开始等待接收反馈            InputStream is;            byte[] arr = new byte[1024];            int len;            try {                is = socket.getInputStream();                len = is.read(arr);//阻塞式方法                System.out.println(new String(arr,0,len));            } catch (IOException e) {                System.out.println("已退出聊天室");//输入886退出后捕获并处理异常            }        }    }}

服务端

import java.io.*;import java.net.ServerSocket;import java.net.Socket;/** * Created by mo on 15/11/21. * 客户端键盘录入,服务器输出到控制台 */public class Server {    public static void main(String[] args) throws IOException {        ServerSocket ss = new ServerSocket(10588);        //在循环里监听并建立Socket连接        while (true){            Socket s = ss.accept();            //把通道内的流给包装一下.因为Socket走的是字节流            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));            String line ;            //IO流获取数据并给予反馈            while ((line = br.readLine()) != null){                System.out.println(s.getInetAddress().getHostAddress()+":"+line);                OutputStream os = s.getOutputStream();                os.write("服务器已接收到信息".getBytes());            }            s.close();        }        //这里也可以采用字节流,但要保证发送端接收端都用的字节流(具体代码为以下注释部分)//        while (true){//            Socket s = ss.accept();//            InputStream br=s.getInputStream();////            int line ;//            byte[] arr = new byte[1024];//            while ((line = br.read(arr)) != -1){//                System.out.println(s.getInetAddress().getHostAddress()+":"+new String(arr,0,line));//                OutputStream os = s.getOutputStream();//                os.write("服务器已接收到信息".getBytes());//            }////            s.close();//        }    }}

案例2:多个客户端上传文件到服务器(多线程解决)
服务器端

import java.io.*;import java.net.ServerSocket;import java.net.Socket;/** * Created by mo on 15/11/21. * * 只用while(true)包起来的缺点:都以一个名称储存 前几个客户端传的被覆盖 只剩最后一个 * * 所以要用多线程 */public class Server {    public static void main(String[] args) throws IOException {        //创建ServerSocket对象        ServerSocket serverSocket = new ServerSocket(25255);        //因为不知道有多少个客户端发送数据,所以这里用while循环监听并为每一个建立连接的客户端启动一个新线程        //接收文件的代码放在线程里处理        while (true) {            Socket s = serverSocket.accept();            Thread thread = new Thread(new serverThread(s));            thread.start();        }    }}/** * 这是服务端接收文件的线程类 */class serverThread implements Runnable {    private Socket s;    public serverThread(Socket s) {        this.s = s;    }    @Override    public void run() {        byte[] arr = new byte[4096];        int len;        try {            BufferedInputStream br = new BufferedInputStream(s.getInputStream());            //这里 多个线程 会覆盖一个文件 所以要改进//            BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("account.txt"));            //改进方法:因为目前无法获取到上传的文件名,所以只能用当前时间毫秒值来命名            String newName = System.currentTimeMillis()+".txt";            BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream(newName));            while ((len = br.read(arr)) != -1) {                bw.write(arr, 0, len);                //重点!这里非常有必要flush()一下,不然会导致,最后一次没有接收,丢失最后一部分                bw.flush();            }            //保存完毕后给予客户端反馈            OutputStream sd = s.getOutputStream();            sd.write("文件上传完毕".getBytes());            bw.close();            s.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

客户端(每个客户端都一样,这里只放一个客户端的代码)

import java.io.*;import java.net.Socket;/** * Created by mo on 15/11/21. * * 多个客户端  1个服务器端 * * 客户端不用修改 只修改服务器端 */public class Client1 {    public static void main(String[] args)throws IOException {        //创建Socket对象 传入目标ip+端口        Socket socket = new Socket("192.168.0.100",25255);        //封装要上传的文件        BufferedInputStream br = new BufferedInputStream(new FileInputStream("/Users/mo/account.txt"));        //获取通道的写入流        BufferedOutputStream bw = new BufferedOutputStream(socket.getOutputStream());        int len;        byte[] arr = new byte[4096];        while ((len=br.read(arr)) != -1){            bw.write(arr,0,len);            //重点!这里非常有必要flush()一下,不然会导致,最后一次没有发送出去,导致传过去的文件丢失一部分            bw.flush();        }        //上传完了就给个结束标记,告诉服务器已经传完了,别等了        socket.shutdownOutput();        //接收服务器端发来的反馈        InputStream rec = socket.getInputStream();        int end ;        byte[] arr1 = new byte[1024];        end = rec.read(arr1);        System.out.println(new String(arr1,0,end));        br.close();        socket.close();    }}
0 0
原创粉丝点击