Java之网络编程Socket

技术:
  • 网络编程Socket
  • 多线程Thread
  • 数据传递
具体实现:

网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。更具体的说,网络编程就是两个或多个程序之间的数据交换。就如我们平常的QQ聊天、打开网易APP刷新界面等,就会有新的数据从它们的服务器端里面获取出来。它们的APP就相当于客户端。还有我们打开一个浏览器,就可以得到一个对应的网页,如我们在浏览器输入一个www.baidu.com,就会显示一个百度的网页,实际上这个网页就是由一些基本数据组成的,而这些基本数据是由百度的服务器获取出来的。

  • 客户端(Client):给我们用户要用的信息就是客户端,如手机APP 浏览器 桌面QQ
  • 服务器端(Server):就是用来存储数据或者说是处理数据的地方


    38.PNG

    我们从客户端访问服务器端就是通过url地址来访问。这里可以知道服务器其实不存储数据,真正存储数据是由数据库来完成的。

  • URL:统一的资源定位(就是大家都用url来找到服务器里面的资源)
    我们通常用的url如:http://www.baidu.com/search?code=andriod&type=1
    在这里
  • http/https:传输协议 Tcp/IP协议
  • www.baidu.com :域名 表示一台网络中的电脑
  • ip地址:唯一标识一台网络中的计算机,每一台电脑都有自己独一的ip地址(ipv4 ipv6)
  • ip地址共有32位,四个部分每个部分8个字节。
    如:ip地址172.20.10.15 <-> www.baidu.com
    由于ip地址的数字有点多和长,不利于记忆。因此开发了域名系统(Domain Name System,DNS)用来将人类易于记忆的主机名(如www.12345.com)转换为数字Internet地址(如208.201.243.99)。当Java程序访问网络时,他们需要同时处理数字地址和相应的主机名。这些方法由java.net.InetAddress类提供。
  • search 对应的后台程序文件 php java jsp
  • ? 表示运行这个程序需要传递的参数
  • code=andriod code是服务器端规定的字段
  • & 如果有多个参数使用&符号链接
/**
* ip地址:唯一标识某一台电脑
 * 端口号:标识这台电脑上运行的某个程序(进程)80
 *
 * 数据传递:Tcp/IP协议
 * TCP:面向连接的 安全的  打电话
 * UDP:面向无连接的 不安全 但快
*/
39.PNG
  • 读取数据:服务器读取 客户端读取
  •      BufferedReader->InputStreamReader->socket.getInputStream();
    
  •      读取终端
    
  •      BufferedReader->InputStringReader->System.in
    
  • 输出:客户端输出 服务器端输出
  •      BufferedWriter->OutputStreamWriter->socket.getOutputStream();
    
  •      PrintStream->socket.getOutputStream();
    
注意:实现客户端和服务器端传递数据: 注意端口号必须相同 先运行Server 再运行Client。
//模拟客户端
class Client{
    public static void main(String[] args)throws IOException{
        //1.创建用于通信的socket
        //  指明和谁通信:ip地址  端口号
        Socket socket = new Socket("192.168.137.1",8989);
        //接收服务器端的数据
        BufferedReader br= new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //socket.getInputStream();
        //向服务器端发送数据
        //socket.getOutputStream();
        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
        //客户端向服务器发送数据
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("hello ");
        socket.shutdownOutput();
    }
}
//模拟服务器端
class Server{
    public static void main(String[] args)throws IOException {
      //1.创建服务器端serverSocket
        ServerSocket ss= new ServerSocket(8989);

        //2.获取连接的客户端的socket
        Socket clientSocket = ss.accept();

        //3.向客户端发送数据   对于字符的输入输出Reader  /  Writer
        //BufferedWriter br = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
        PrintStream ps = new PrintStream(clientSocket.getOutputStream());
        ps.println("你已登陆成功");

        clientSocket.shutdownOutput();//告诉客户端输出完毕

        //4.服务器端接收客户端发来的数据
        BufferedReader br= new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}

运行结果:


GIF.gif

这里就成功实现了客户端向服务器端输入“Hlleo”,服务器端向客户端输出“登陆成功”。实现了数据的相互传输。
我们上面这个程序代码不能实现从服务器端手动的输入输出。接下啦我们来实现服务器端的手动的输入。将输入的内容发送给客户端可以一直发。

class MyClinet{
    public static void main(String[] args){
        //连接服务器端的socket
        Socket socket = null;
        try {
             socket = new Socket("192.168.137.1",8888);
             //接收服务器端信息
            BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line =null;
            while ((line= br.readLine()) !=null){
                System.out.println(line);
            }
            //从键盘输入数据 发送给终端
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("网络出错  请重新输入");
        }finally {
            //关闭连接
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
class MyServer{
    public static void main(String[] args){
        //创建ServerSocket
        try (ServerSocket ss= new ServerSocket(8888)){
             //监听客户端
            Socket socket = ss.accept();

            //从终端接收数据
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            //获取向客户端输出数据的输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            String line = null;
            while ((line=keyin.readLine())!= null){
                //发送给客户端
                ps.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 手动收入内容 发送

  • socket扮演的是客户端

  • ServerSocket扮演的是服务器端

  • 客户端 1.文本 2.图片 3.视频 4.音频 服务器端 只要是数据都可在两者之间进行传递

    运行结果:
    GIF.gif6.gif

    在这里就实现了从服务器端的手动输入,将输入的内容发送给客户端。

    前面我们说了在客服端和服务器端可以实现 1.文本 2.图片 3.视频 4.音频等等的传递。

实现客户端向服务器端上传图片
/**
 * 客户端向服务器端发送图片
 * post上传
 */
class Client{
    public static void main(String[] args) throws IOException {
        //连接服务器 获取socket
        Socket socket = new Socket("192.168.137.1",8080);

        //创建服务器端对应的输入流 用于接收服务器端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        System.out.println(br.readLine());

        //向服务器端发送文件(图片)
        //1.将文件写入到内存里
        String path ="C:\\Users\\DAMEI\\Desktop\\1.jpg";
        FileInputStream fis = new FileInputStream(path);

        //2.创建字节流 outputStream
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        byte[] buf = new byte[1024];
        int len = -1;
        while ((len = fis.read(buf)) != -1){
            bos.write(buf,0,len);
        }
        socket.shutdownOutput();
    }
}
class Server{
    public static Iterable<? extends Socket> sockets;

    public static void main(String[] args) throws IOException {
        //创建服务器端的ServerSoket
        ServerSocket ss = new ServerSocket(8080);

        //监听客户端连接
        //当有客户端来连接这个服务器 就可以得到对应的socket
        //当没有客户端来连接 服务器一直在这里等待
        Socket socket = ss.accept();

        //创建客户端对应的输出流 用于向这个客户端发送数据
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("连接成功 可以发数据了!");

        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        String path ="D:\\android study\\yjx1\\src\\main\\java\\swu\\yjx\\day12media\\picture";
        FileOutputStream fos = new FileOutputStream(path);

        byte[] buf = new byte[1024];
        int len = -1;
        while((len = bis.read(buf)) != -1){
            fos.write(buf,0,len);
        }
    }
}

在这个程序代码里,我的电脑运行出来没有把图片给输出来,不知道是路径还是哪里错了,还得找找。基本上的代码就是这样的。
我们前面的实现只是图片和服务器手动的输入,并没有实现不仅能从客户端输入,也能从服务器端输入。

实现多线程对聊:
 * 客户端和服务器端都可以随意的发送内容
 * 从终端输入
 *
 * 实际就是客户端和服务器端在对聊
 * 客户端:
 *       主线程:接收终端的输入  将终端输入发送给服务器端
 *       子线程:接收服务器端发过来的数据
 *
 *服务器端:
 *        主线程:接收终端输入  将终端输入发送给客户端
 *        子线程:接收客户端发过来的数据

客服端:

class Client1{
    public static void main(String[] args) throws IOException {
        //连接socket
        Socket socket = new Socket("127.0.0.1",8888);

        //用一个子线程处理服务器端的数据
        new Thread(new ClientThread(socket)).start();

        //主线程处理终端输入 发送给服务器
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        String line= null;

        while ((line=keyin.readLine())!=null){
            ps.println(line);
        }


    }
}

/**
 * 创建一个子线程处理客户端接收服务器端的数据
 */
class ClientThread implements Runnable{
    private Socket socket;

    //保存操作的socket对象
    public ClientThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            //获取服务器短的输入流对象
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //读取数据
            String line = null;
            while((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                if(br != null) {
                    br.close();
                }
                if(socket != null){
                    socket.close();
                }
            } catch (IOException e) {
                System.out.println("网络出错,请重新登录!");
                System.exit(-1);
            }

        }

    }
}

服务器端:

class Server1{
    public static void main(String[] args) throws IOException {
        ServerSocket ss= new ServerSocket(8888);

        //获取客户端的socket
        Socket socket = ss.accept();

        //创建子线程 处理客户端输入信息
        new ServerThread(socket).start();

        //终端输入流对象
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        //客户端输出流对象
        PrintStream ps = new PrintStream(socket.getOutputStream());
        //读取终端的输入 将输入对象发送客户端
        //主线程
        String line = null;
        while ((line = keyin.readLine()) !=null){
            ps.println(line);
        }
    }
    }
/**
 *创建一个子线程用于处理服务器端接收客户端的数据
 * */
class ServerThread extends Thread{
    private  Socket socket;
    public ServerThread(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
           br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line =null;
            while ((line= br.readLine())!= null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络异常 请重新登陆");
            System.exit(-1);
        }finally {
            //关闭输入输出流
            //关闭对应的socket连接
            try {
                if (br!=null){
                br.close();
                }
                if (socket!=null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:


GIF.gif7.gif
实现群聊 Client和ClientThread代码和对聊不变

主要在Server里添加数组和监听客户端连接
服务器端:

class Server{
    //保存每一个连接过来的socket对象
    public static ArrayList<Socket> sockets =new ArrayList<>();

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

        //不停的等待客户端来连接
        while (true) {
            Socket socket = ss.accept();
            //当有客户端连接过来了就保存
            sockets.add(socket);

            //开启一个线程处理每个客户端的输入
            new ServerThread(socket).start();


        }
    }
}
/**
 *创建一个子线程用于处理服务器端接收客户端的数据
 * */
class ServerThread extends Thread{
    private  Socket socket;
    public ServerThread(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line =null;
            while ((line= br.readLine())!= null){
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络异常 请重新登陆");
            System.exit(-1);
        }finally {
            //关闭输入输出流
            //关闭对应的socket连接
            try {
                if (br!=null){
                    br.close();
                }
                if (socket!=null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端:

class Client2{
    public static void main(String[] args) throws IOException {
        //连接socket
        Socket socket = new Socket("192.168.137.1",6666);

        //用一个子线程处理服务器端的数据
        new Thread(new ClientThread(socket)).start();

        //主线程处理终端输入 发送给服务器
        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        String line= null;

        while ((line=keyin.readLine())!=null){
            ps.println(line);
        }


    }
}

/**
 * 创建一个子线程处理客户端接收服务器端的数据
 */
class ClientThread implements Runnable{
    private Socket socket;
    //构造方法 保存数据对象
    public ClientThread(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //读取数据
            String line = null;
            while ((line=br.readLine())!=null){
                //群发消息
                //遍历Server维护的数组
                for(Socket socket: Server.sockets){
                    //向socket对应的客户端发送消息
                    PrintStream ps = new PrintStream(socket.getOutputStream());
                }
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("网络异常 请重新登陆");
            e.printStackTrace();
        }finally {
            try {
                if (br != null)
                {br.close();
                } if (socket != null){
                    socket.close();}
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

总结:以上就是Java中的基本的网络编程大概。在这里我们不仅实现了图片的上传、手动的从服务器端输入,还实现了客户端和服务器端的对聊及群聊。在这里也运用到了很多我们以前所讲到的东西。如:

  • 多线程Thread
  • while和for循环
  • run方法
  • 继承extends
  • 接口implements
  • 处理异常throws
  • 构造方法
    等等。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 计算机网络概述 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。 按照计算机网络的定义,通过一定...
    蛋炒饭_By阅读 1,209评论 0 10
  • 网络编程 一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运...
    go以恒阅读 1,988评论 0 6
  • 说明 本文 翻译自 realpython 网站上的文章教程 Socket Programming in Pytho...
    keelii阅读 2,100评论 0 16
  • 1.网络编程1.1计算机网络概述网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。按照计算机网络的...
    任振铭阅读 421评论 0 1
  • 别再迷茫了,对你没有好的结果
    小鬼gl阅读 137评论 0 0