网络编程--Java学习记录24天

通信一定是基于软件结构的:
1.C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。
2.B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构 常见浏览器有谷歌、火狐等、京东、淘宝。(开发中的重点,基于网页设计界面,界面效果可以更丰富)

网络通信的三要素。

1.协议
    - 协议:计算机网络客户端与服务端通信必须事先约定和彼此遵守的规则,

2.IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。
        IP地址用来给一个网络中的计算机设备做唯一的编号.
  IPv4:4个字节,32位组成。  
        局域网,城域网,广域网(公网)
        已经分配完了,不够用。
        局域网:公司内部用。
        公网:可以在任何地方访问。
  IPv6:可以实现为所有设备分配IP
  ipconfig:查看本机的IP
  ping:检查本机与某个IP指定的机器是否联通,或者说是检测对方是否在线。
  ping 空格 IP地址
  ping 
  ping www.baidu.com
  特殊的IP地址: 本机IP地址127.0.0.1、localhost
3.端口:端口号就可以唯一标识设备中的进程(应用程序)了
    端口号:用两个字节表示的整数,它的取值范围是0~65535
    0~1023之间的端口号用于一些知名的网络服务和应用,数据库MYSQL端口为3306;
    普通的应用程序需要使用1024以上的端口号。
    如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
    利用协议+IP地址+端口号三元组合,
    就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。

网络通信的分层和协议。

网络通信协议:通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信。

应用层  :应用程序(QQ,浏览器),可能用到的协议(HTTP,FTP,SMTP)   通常程序员只需要关心这一层
------------------------------------------------------------------------------
传输层  :TCP/IP协议 UDP协议    计算机网络工程师需要精通的协议,有些技术我们也需要精通这一层协议,以后再学习!
---------------------------------------------------------
网络层  :IP协议
--------------------------------------------------------------
数据链路层 : 进入到硬件(网)
物理层

TCP/IP协议:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的安全的可靠的传输通信协议。
    1.在通信之前必须确定对方在线并且连接成功才可以通信。
    2.例如下载文件、浏览网页等(可靠传输)

UDP:用户数据报协议(User Datagram Protocol)。UDP协议是一个面向无连接的不可靠传输的协议。
    1.直接发消息给对象,不管对方是否在线,发消息后也不需要确认。
    2.无线(视频会议,通话),性能好,丢失一些数据!!

TCP通信系列技术:Socket通信(BIO),NIO , NIO2 , AIO , Netty
目标:Socket网络编程。

Socket(套接字,端口):端到端的通信,只要是基于Socket在通信,那么我们就是默认基于了TCP/IP协议通信的。
Socket网络编程是Java提供的基于TCP/IP的有连接的可靠传输协议。

需要提供一个客户端 和 一个服务端。
需求:客户端发送一个消息给服务端,服务端收到客户端的消息输出即可!!(一发一收)

Java是通过java.net.Socket类来实现的。

(1)先开发服务端
    a.注册端口
        --  public ServerSocket(int port):
        ServerSocket serverSocket = new ServerSocket(9999);
    b.等待客户端的请求连接得到一个Socket通信管道。
        --  public Socket accept()
        Socket socket = serverSocket.accept();
    c.从Socket管道中得到字节输入流
        -- public InputStream getInputStream()
        InputStream is = socket.getInputStream();
    d.从字节输入流中读取客户端发送来的消息。

(2)开发客户端
    a.请求与服务端的Socket管道的连接。
        --    public Socket(String host, int port)
        Socket socket = new Socket("192.168.**.**1",9999);
    b.从Socket管道中得到一个字节输出流。
        --    public OutputStream getOutputStream()
        OutputStream os = socket.getOutputStream();
    c.用这个字节输出流写出数据到服务端。

    通信是很严格的,客户端怎么发,服务端就怎么收,
    客户端发了多少,服务端就只能接收多少!!

一发一收:分别为客户端和服务端

/**
    目标:一发一收,服务器再响应接收成功的数据
 */
public class ClientDemo {
    public static void main(String[] args) throws Exception {
        //  a.请求与服务端的Socket管道的连接。
        Socket socket = new Socket("127.0.0.1",9989);
        //  b.从Socket管道中得到一个字节输出流。
        OutputStream os = socket.getOutputStream();
        //  c.写数据出去
        // 把字节输出流包装成打印流写数据给服务器
        PrintStream ps = new PrintStream(os);
        ps.println("我是客户端,我给你发了,约吗?");
        ps.flush();

        // 读取服务端响应的消息
        // 从Socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null ;
        if((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args) throws Exception {
        System.out.println("----服务器被启动----");
        // a.注册端口得到监听客户端的对象:serverSocket
        ServerSocket serverSocket = new ServerSocket(9989);
        // b.通过ss对象等待客户端的请求连接得到一个Socket通信管道。
        Socket socket = serverSocket.accept();
        // c.从Socket管道中得到字节输入流
        InputStream is = socket.getInputStream();
        // d.从字节输入流中读取客户端发送来的消息。
        // 把字节输入流管道改装成高级缓冲字节输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        // 开始按照行读取客户端发来的消息
        String line = null ;
        if((line = br.readLine()) != null){
            System.out.println("服务端收到:"+line);
        }

        // 响应一个接收成功的消息发送回给客户端。
        // 从Socket管道中得到一个字节输出流
        OutputStream os = socket.getOutputStream();
        // 把字节输出流包装成打印流
        PrintStream ps = new PrintStream(os);
        ps.println("服务器已收到您的消息 200 Ok!");
        ps.flush();

        // 服务器死的晚一点,等客户端收到后再死亡
        Thread.sleep(2000);
    }
}

目标:客户端可以反复的发消息,服务端可以反复的收消息。

import java.io.*;
import java.net.Socket;
import java.util.Scanner;


public class ClientDemo {
    public static void main(String[] args) throws Exception {
        //  a.请求与服务端的Socket管道的连接。
        Socket socket = new Socket("127.0.0.1",9999);
        //  b.从Socket管道中得到一个字节输出流。
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);
        while(true){
            //  c.创建一个扫描器反复接收用户键盘的输入
            Scanner scn = new Scanner(System.in);
            String msg = scn.nextLine();
            // 写一行消息给服务端
            ps.println(msg);
            ps.flush();
        }
    }
}

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args)  {
        try{
            System.out.println("----服务器被启动----");
            // a.注册端口得到监听客户端的对象:serverSocket
            ServerSocket serverSocket = new ServerSocket(9999);
            // b.通过ss对象等待客户端的请求连接得到一个Socket通信管道。
            Socket socket = serverSocket.accept();
            // c.从Socket管道中得到字节输入流
            InputStream is = socket.getInputStream();
            // d.从字节输入流中读取客户端发送来的消息。
            // 把字节输入流管道改装成高级缓冲字节输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            // 开始按照行读取客户端发来的消息
            String line = null ;
            while((line = br.readLine()) != null){
                System.out.println("服务端收到:"+line);
            }
        }catch (Exception e){
            // 说明客户端下线了
            System.out.println("客户端离线了!!");
        }
    }
}

服务端可以接收无数个客户端的消息,可以反复发,反复收(群聊)

解决方案:如果服务端需要接收多个客户端的连接,服务端必须实现一个客户端一个线程处理!
引入多线程。

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientDemo {
    public static void main(String[] args) throws Exception {
        //  a.请求与服务端的Socket管道的连接。
        Socket socket = new Socket("192.168.**.**1",9999);
        //  b.从Socket管道中得到一个字节输出流。
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);
        while(true){
            //  c.创建一个扫描器反复接收用户键盘的输入
            Scanner scn = new Scanner(System.in);
            String msg = scn.nextLine();
            // 写一行消息给服务端
            ps.println(msg);
            ps.flush();
        }
    }
}
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args)  {
        try{
            System.out.println("----服务器被启动----");
            // a.注册端口得到监听客户端的对象:serverSocket
            ServerSocket serverSocket = new ServerSocket(9999);
            while(true){
                // b.通过ss对象等待客户端的请求连接得到一个Socket通信管道。
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress()+"上线,来了老弟!");
                // 每次接收到一个客户端的通信请求后服务端就为这个管道创建一个线程来处理它
                new MyServerReaderThread(socket).start();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

class MyServerReaderThread extends Thread{
    private Socket socket;

    public MyServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try{
            // c.从Socket管道中得到字节输入流
            InputStream is = socket.getInputStream();
            // d.从字节输入流中读取客户端发送来的消息。
            // 把字节输入流管道改装成高级缓冲字节输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            // 开始按照行读取客户端发来的消息
            String line = null ;
            while((line = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress()+"说了:"+line);
            }
        }catch (Exception e){
            System.out.println(socket.getRemoteSocketAddress()+"下线了!");
        }
    }
}

客户端:
目标:文件上传。 客户端的文件,服务端的存储目录。
服务器的目录:D:\腾讯图片资源服务器
上传图片:D:\图片资源\meinew01.jpg

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


public class ClientDemo {
    /** (1)定义发送图片的路径。 */
    public static final String SRC_FILE = "D:\\图片资源\\m01.jpg";

    public static void main(String[] args) {

        try {
            /** (2)请求服务端的Socket通信管道连接 */
            Socket socket = new Socket("192.168.**.***", 8888);
            /** (3)定义一个字节输入流读取源文件  */
            InputStream is = new FileInputStream(SRC_FILE);
            /** (4)从Socket管道中得到一个字节输出流*/
            OutputStream os = socket.getOutputStream();
            /** (5)从字节输入流中读取文件数据写出到字节输出流管道*/
            int len = 0 ;
            byte[] buffer = new byte[1024];
            while((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            os.flush();
            socket.shutdownOutput(); // 通知服务端我已经发送完毕,请你不用再等我了!

            // 接收上传后的结果
            // 读取服务端响应的消息
            // 从Socket通信管道中得到一个字节输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null ;
            if((line = br.readLine()) != null){
                System.out.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;

/**
    目标:服务端开发

    服务器开发分析:
        (1)注册端口
        (2)定义一个循环接收客户端的请求交给一个独立的多线程(接收无数客户端)
        (3)在线程中处理这个客户端读取文件数据。
        (4)从Socket管道中得到一个字节输入流。
        (5)定义一个字节输出流与服务器的目录连通。
        (6)从字节输入流中读取数据写出到字节输出流
 */
public class ServerDemo {
    // 定义服务器的文件目录
    public static final String DEST_FILE = "D:\\腾讯图片资源服务器\\";

    public static void main(String[] args)  {
        try{
            System.out.println("----服务器被启动----");
            /** (1)注册端口 */
            ServerSocket serverSocket = new ServerSocket(8888);
            while(true){
                /** (2)定义一个循环接收客户端的请求交给一个独立的多线程(接收无数客户端) */
                Socket socket = serverSocket.accept();
                new MyServerReaderThread(socket).start();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

class MyServerReaderThread extends Thread{
    private Socket socket;

    public MyServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try{
            /** (3)在线程中处理这个客户端读取文件数据。 */
            /** (4)从Socket管道中得到一个字节输入流。*/
            InputStream is = socket.getInputStream();


            /**(5)定义一个字节输出流与服务器的目录连通。 */
            OutputStream os = new FileOutputStream(ServerDemo.DEST_FILE+ UUID.randomUUID().toString()+".jpg");
            /**(6)从字节输入流中读取数据写出到字节输出流 */
            int len = 0 ;
            byte[] buffer = new byte[1024];
            while((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            os.close();

            // 响应数据给客户端
            // 响应一个接收成功的消息发送回给客户端。
            // 从Socket管道中得到一个字节输出流
            // 把字节输出流包装成打印流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println("服务器已收到您的文件! 200 Ok!");
            ps.flush();
            // 服务器死的晚一点,等客户端收到后再死亡
            Thread.sleep(2000);
        }catch (Exception e){
            System.out.println(socket.getRemoteSocketAddress()+"下线了!");
        }
    }
image.png

编写程序满足上图要求:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        try {
            //与服务端连接
            Socket socket = new Socket("127.0.0.1", 22228);
            //把输出流包装成高级流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            //提示客户输入格式
            System.out.println("请输入您的用户名和密码,格式如:admin=123456");
            //创建扫描器,等待客户输入
            Scanner sc = new Scanner(System.in);
            String date = sc.nextLine();
            //把用户名和密码打印出来
            ps.println(date);
            ps.flush();


            //响应服务端
            BufferedReader bf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("收到服务端响应:"+bf.readLine());
            bf.close();
            ps.close();
            socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        try {
            //建立端口与服务端连接
            ServerSocket serverSocket = new ServerSocket(22228);
            while (true){
                //开始接收客户端的socket管道请求
                Socket socket = serverSocket.accept();
                //创建一个线程来处理
                new ReadThread(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class ReadThreads extends  Thread {
    private Socket socket;
    public ReadThreads(Socket socket) {
        this.socket = socket; }
        //从socket管道包装成高级缓冲流管道

    @Override
    public void run() {
        BufferedReader br;

        {
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //读取客户登录信息:ademin = 12345
                String line = br.readLine();

                //建立集合存储客户信息
                Map<String,String> nameAndPsw = new HashMap<>();

                //从文件读取信息
                BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\IdeaProjects\\users.txt")));
                String ln = null;
                while ((ln = bfr.readLine())!=null){
                    String[] name = ln.split(",");
                    nameAndPsw.put(name[0],name[1]);
                }
//            System.out.println(nameAndPsw);
                //比较客户输入信息与文件信息是否一样
                String[]  names = line.split("=");
                String name1 = names[0];
                String pwd1 = names[1];
                PrintStream ps = new PrintStream(socket.getOutputStream());
                if(nameAndPsw.containsKey(name1)){
                    if(nameAndPsw.containsValue(pwd1)){
                        ps.println("登录成功");
                    }else{
                        ps.println("密码错误");
                    }
                }else {
                    ps.println("用户名错误");
                }
               ps.flush();
                Thread.sleep(2000);
                ps.close();
                br.close();
                bfr.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,289评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 95,968评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 171,336评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,718评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,734评论 6 399
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,240评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,631评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,599评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,139评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,166评论 3 345
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,286评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,917评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,604评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,075评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,205评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,814评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,351评论 2 365

推荐阅读更多精彩内容

  • 计算机网络概述 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。 按照计算机网络的定义,通过一定...
    蛋炒饭_By阅读 1,232评论 0 10
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,119评论 1 32
  • 网络编程的概述 网络编程的实质就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。 一.OSI网络模型...
    思念挥霍阅读 382评论 0 0
  • 1.网络编程1.1计算机网络概述网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。按照计算机网络的...
    任振铭阅读 427评论 0 1
  • 路遇两万初夜女 经这么一闹,倒是让程诺无意间摆脱了两个美女的“讨伐”,特别的王梦妍,她现在只顾着在自己的位置上哀怨...
    诺阳阁阅读 371评论 0 0