java回顾之Socket网络编程

java回顾之Socket网络编程

一、软件结构

C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件

特点:

  优点:
    对网络要求不是很高
  缺点:
    开发维护周期长
    占用空间

B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等

 特点 

  优点:
    开发维护周期短
    不占用空间
  缺点:
    对网络网速要求高

二、网络编程三要素

ip地址:

    ip地址是计算机的唯一标识。互联网上面的每个设备都有唯一的ip地址

    查ip的命令:ipconfig

  ip的分类

  IPV4:有4个255的段落,192.168.31.56。IPV4已经被全世界的设备用光了

  IPV6: ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 ,号称能给世界的每一粒沙子分配一个不重复的IP

端口号:

  端口号是软件的唯一标识。每个软件都有一个唯一的端口号,范围是0~65535,其中0~1023是留给系统使用的要 避开。

协议:  

  协议是传输数据的方式

  TCP:面向连接,安全,效率低

  三次握手

  UDP:面向无连接,不安全,效率高,对数据包有大小限制不能超过64K

三、InetAddress类

InetAddress类成员方法
  * static InetAddress getLocalHost()
获得本地主机IP地址对象
  * static InetAddress getByName(String host)
根据IP地址字符串或主机名获得对应的IP地址对象

  * String getHostName() 获得主机名
  * String getHostAddress() 获得IP地址字符串

四、TCP通信程序

代码演示:

    客户端发送数据

public class Demo客户端 {
    public static void main(String[] args) throws IOException {

        //创建套接字对象
        //客户端要指定给谁发送数据
        //第一个参数是对方的ip  第二个参数是对方的端口
        Socket s = new Socket("192.168.31.87",8888);

        //Socket里面包含输出流和输入流,我们网络编程需要获取底层流完成数据发送

        //获取输出流
        OutputStream os = s.getOutputStream();
        //键盘输入内容发送
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        //输出(把字符串转成字节数组)
        os.write(str.getBytes());


        //关闭资源
        s.close();
    }
}

    服务端接收数据

public class Demo服务器端 {
    public static void main(String[] args) throws IOException {
        //创建服务器对象
        //参数代表的是自己的端口
        ServerSocket ss = new ServerSocket(8888);

        //接受客户单的连接
        //阻塞(如果连接不到客户端就会一直等待)
        Socket s = ss.accept();

        //获取输入流
        InputStream is = s.getInputStream();

        //接受数据
        byte[] arr = new byte[1024];
        //默认发送的时候就只发了一句话,不需要使用循环读取
        int len = is.read(arr);

        //打印
        System.out.println("客户端对我说:" + new String(arr,0,len));

        //关闭资源
        s.close();
        //ss.close();服务器打开之后一般不会关闭
    }
}

 4.3、TCP模拟聊天

        客户端代码
   public class Demo客户端 {
    public static void main(String[] args) throws IOException {

        //创建套接字对象
        //客户端要指定给谁发送数据
        //第一个参数是对方的ip  第二个参数是对方的端口
        Socket s = new Socket("192.168.31.87",9999);

        //Socket里面包含输出流和输入流,我们网络编程需要获取底层流完成数据发送

        while(true) {
            //获取输出流
            OutputStream os = s.getOutputStream();
            //键盘输入内容发送
            Scanner sc = new Scanner(System.in);
            String str = sc.nextLine();
            //输出(把字符串转成字节数组)
            os.write(str.getBytes());


            //接受数据
            //获取输入流
            InputStream is = s.getInputStream();
            byte[] arr = new byte[1024];
            //读取内容
            int len = is.read(arr);
            //打印
            System.out.println("服务器对我说: " + new String(arr, 0, len));

        }

        //关闭资源
        //s.close();
    }
}

  

 服务端代码:

public class Demo服务器端 {
    public static void main(String[] args) throws IOException {
        //创建服务器对象
        //参数代表的是自己的端口
        ServerSocket ss = new ServerSocket(9999);

        //接受客户单的连接
        Socket s = ss.accept(); //阻塞(如果连接不到客户端就会一直等待)

        while(true) {

            //获取输入流
            InputStream is = s.getInputStream();
            //接受数据
            byte[] arr = new byte[1024];
            //默认发送的时候就只发了一句话,不需要使用循环读取
            int len = is.read(arr);
            //打印
            System.out.println("客户端对我说:" + new String(arr, 0, len));


            //发送数据
            //获取输出流
            OutputStream os = s.getOutputStream();
            //发送固定语句
            os.write("滚".getBytes());

        }

        //关闭资源
        //s.close();
        //ss.close();服务器打开之后一般不会关闭

    }
}

  

4.4、文件上传案例

客户端发送文件
public class Demo文件上传的客户端 {
    public static void main(String[] args) throws IOException {

        //创建对象
        //Socket s = new Socket("127.0.0.1",5678);
        //Socket s = new Socket("localhost",5678);
        Socket s = new Socket("192.168.31.87",5678);

        //创建输入流
        FileInputStream fis = new FileInputStream("C:\资料\小资料\微信图片_20190108110420.jpg");
        //获取输出流
        OutputStream os = s.getOutputStream();

        //每次读取一个字节发送给服务器
        int i;
        while((i = fis.read()) != -1){
            //输出
            os.write(i);
        }

        //关闭资源
        fis.close();
        s.close();
    }
}


    服务器接收文件
public class Demo文件上传的服务器端 {
    public static void main(String[] args) throws IOException {

        //创建对象
        ServerSocket ss = new ServerSocket(5678);
        //获取客户端连接
        Socket s = ss.accept();

        //获取输入流
        InputStream is = s.getInputStream();
        //创建输出流
        FileOutputStream fos = new FileOutputStream("day18\上传图片.jpg");

        //每次读取一个字节输出一个字节
        int i;
        while ((i=is.read()) != -1){
            fos.write(i);
        }

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

 有个循环发送的问题。 

解决办法:

  

  • 客户端停止发送数据之后,需要通知服务器:

        s.shutdownOutput();

4.6、模拟B/S服务器

B/S模式是web的内容,以下是服务器需要给浏览器发送的响应信息,在正式传输数据前,要先写这个。
- 

```
发送图片:
	"HTTP/1.1 200 OK
Content-Type:image/jpeg

"
发送文字时:
	"HTTP/1.1 200 OK
Content-Type:text/html;charset=UTF-8

"
```

- 服务器端
public class Demo服务器 {

    public static void main(String[] args) {
        try {
            //创建服务器对象
            ServerSocket ss = new ServerSocket(7890);

            while (true) {
                //接受浏览器的请求
                Socket s = ss.accept();
                //获取输入流
                InputStream is = s.getInputStream();

                //调用读取一行字符串的方法
                //readLine()
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String str = br.readLine();
                //从浏览器发过来的数据
                //System.out.println(str);   //  GET /1.jpg HTTP/1.1

                //1.截取用户要访问的资源名称
                String[] arr = str.split(" ");
                String name = arr[1];  //    /1.jpg

                //2.查找文件是否存在
                File f = new File("day18/发车" + name);  //路径: day18/发车/4.jpg

                //3.获取输出流
                BufferedOutputStream os = new BufferedOutputStream(s.getOutputStream());

                if (f.exists()) {
                    //4.创建输入流
                    BufferedInputStream fis = new BufferedInputStream(new FileInputStream(f));

                    //要访问的资源存在
                    //如果存在把图片发送给浏览器
                    os.write("HTTP/1.1 200 OK
Content-Type:image/jpeg

".getBytes());
                    //发送数据
                    int i;
                    while ((i = fis.read()) != -1) {
                        os.write(i);
                    }

                    //关流
                    fis.close();

                } else {
                    //要访问的资源不存在
                    //如果不存在给浏览器"你要访问的资源被外星人劫持了404~"
                    os.write("HTTP/1.1 200 OK
Content-Type:text/html;charset=UTF-8

".getBytes());
                    os.write("你要访问的资源被外星人劫持了404~".getBytes());

                }
                //关流
                os.close();

                //关闭
                s.close();

            }

        }catch (Exception e){
            //如果你想看报错信息
            //e.printStackTrace();
        }

    }
}

- 上面的代码是单线程代码,当多个浏览器都访问同一个服务器时。服务器需要一个一个处理。
- 接下来我们写一个多线程代码。为每一次访问都开启一个线程

public class Demo服务器多线程 {
    public static void main(String[] args) throws Exception{

            //创建服务器对象
            ServerSocket ss = new ServerSocket(7890);
            //可以接受多个浏览器的访问
            while(true){
                //接受浏览器的请求
                Socket s = ss.accept();
                //每次接收到浏览器请求就开启新线程
                //使用Lambda表达式开启多线程(Runnable是一个函数式接口)
                Thread t = new Thread(()->{

                    try {
                        //获取输入流
                        InputStream is = s.getInputStream();

                        //调用读取一行字符串的方法
                        //readLine()
                        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        String str = br.readLine();
                        //从浏览器发过来的数据
                        //System.out.println(str);   //  GET /1.jpg HTTP/1.1

                        //1.截取用户要访问的资源名称
                        String[] arr = str.split(" ");
                        String name = arr[1];  //    /1.jpg

                        //2.查找文件是否存在
                        File f = new File("day18/发车" + name);  //路径: day18/发车/4.jpg

                        //假设每次执行都需要3秒钟,这样为了看到多线程的效果
                        Thread.sleep(3000);

                        //3.获取输出流
                        BufferedOutputStream os = new BufferedOutputStream(s.getOutputStream());

                        if (f.exists()) {
                            //4.创建输入流
                            BufferedInputStream fis = new BufferedInputStream(new FileInputStream(f));

                            //要访问的资源存在
                            //如果存在把图片发送给浏览器
                            os.write("HTTP/1.1 200 OK
Content-Type:image/jpeg

".getBytes());
                            //发送数据
                            int i;
                            while ((i = fis.read()) != -1) {
                                os.write(i);
                            }

                            //关流
                            fis.close();

                        } else {
                            //要访问的资源不存在
                            //如果不存在给浏览器"你要访问的资源被外星人劫持了404~"
                            os.write("HTTP/1.1 200 OK
Content-Type:text/html;charset=UTF-8

".getBytes());
                            os.write("你要访问的资源被外星人劫持了404~".getBytes());


                        }
                        //关流
                        os.close();

                        //关闭
                        s.close();
                    }catch (Exception e){
                        //异常处理
                    }
                });
                t.start();
            }
    }
原文地址:https://www.cnblogs.com/gushiye/p/13894210.html