Java实现TCP通信-----Socket类和ServiceScoket类------使用ServiceSocket类模拟服务器

目录

 

1、概述

2、Socket类

3、ServiceSocket类

4、简单的客户端服务端通信代码 

4-1、服务器端

4-2、客户端

5、模拟B\S服务器

总结:


1、概述

TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。Java提供了两个类用于TCP通信程序

1、客户端:java.new.Socket类。创建Socket对象,向服务器发出连接请求,服务器端响应请求,两者建立连接开始通信

2、服务器端:java.net.ServiceSocket。创建ServiceSocket对象,相当于开一个服务,并等待客户端的连接

2、Socket类

该类实现客户端套接字,套接字指的是设备之间通信的端点

构造方法

public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指 定的host是null ,则相当于指定地址为回送地址

 构造方法使用举例

Socket client = new Socket("127.0.0.1", 10001);

成员方法

public InputStream getInputStream() : 返回此套接字的输入流。

如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。 关闭生成的InputStream也将关闭相关的Socket。

public OutputStream getOutputStream() : 返回此套接字的输出流。

如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。 关闭生成的OutputStream也将关闭相关的Socket。

public void close() :关闭此套接字。

一旦一个socket被关闭,它不可再使用。 关闭此socket也将关闭相关的InputStream和OutputStream 。

public void shutdownOutput() : 禁用此套接字的输出流。  任何先前写出的数据将被发送,随后终止输出流

3、ServiceSocket类

 该类实现了服务器套接字,该对象等待接收通过网络的请求

构造方法

public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指 定的端口号上,参数port就是端口号

构造方法使用举例

ServerSocket server = new ServerSocket(10001);

 成员方法:

public Socket accept():侦听并接受连接,返回一个新的Socket对象,用于和客户端shi实现通信。该方法会一直处于阻塞态,直到建立连接。

4、简单的客户端服务端通信代码 

无论是客户端向服务器端写数据,还是服务器回写给客户端数据都是一些流的传递,所以在这里接收数据也好,发送数据也好,都可以使用四类流对象及其子类进行操作(四类流对象:InputStream,OutputStream,Reader,Writer)。

4-1、服务器端

package mytest.newChat;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {
    public static void main(String[] args) throws IOException {
        //创建ServiceScoket对象,并设置端口号为9961
        ServerSocket ss = new ServerSocket(9961);
        Scanner sc = new Scanner(System.in);
        //创建一个无限循环,来保证可以循环发送和接受数据
        while (true) {
            System.out.println("================读===================");
            //调用ServiceScoket的accept方法,接收连接,并返回Scoket
            Socket s = ss.accept();
            //获取客户端发送过来的信息
            InputStream is = s.getInputStream();
            //翻译用户发送的信息,并打印在控制台
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = is.read(bytes)) != -1) {
                System.out.println(new String(bytes, 0, len));
            }
            //下面服务器回写给客户端的操作
            System.out.println("================回写================");
            //调用Scoket的getOupputStream()方法,返回此服务器的输出流
            OutputStream os = s.getOutputStream();
            //输入要回写的信息
            String str = sc.next().trim();

            String strClient = "服务器端:" + str;
            //将要回写的信息翻译成字节流并回写
            os.write(strClient.getBytes());

            //关闭资源
            os.close();
            is.close();

        }

    }
}

4-2、客户端

package mytest.newChat;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        while (true){
            //创建Scoket对象,并设置要访问的服务的IP和端口号
            Socket socket = new Socket("localhost", 9961);
            System.out.println("================写================");
            //返回此客户端的一个输出流
            OutputStream os = socket.getOutputStream();
            String str = sc.next().trim();
            String strClient = "客户端:" + str;
            //将客户要发送的信息翻译成字节文件,发送出去
            os.write(strClient.getBytes());
            //发送一个终结符,告诉服务器,已经发送完毕
            socket.shutdownOutput();
            //以下是获取服务器回写的数据
            System.out.println("================读================");
            //返回此客户端的一个输入流
            InputStream is = socket.getInputStream();
            //将服务器回写的数据进行翻译,并打印在控制台
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = is.read(bytes)) != -1) {
                System.out.println(new String(bytes, 0, len));
            }
            //关闭资源
            is.close();
            os.close();
        }



    }
}

5、模拟B\S服务器

在写代码之前,我先将事先写好的前端页面放在当前项目下面,这也代表将web项目放在了服务器下面

我们先来分析一下浏览器是如何访问到服务器上的web项目的

1、首先,浏览器本身就是一个客户端,其向服务端发送访问的请求,而服务端获取来自客户端的请求,查找服务器上是否有客户端所需要的数据,在进一步将客户端所需要的数据回写给客户端,也就是浏览器。

我们先简单的写一个服务器端程序来获取浏览器发送的请求,看下浏览器发送的是什么!

服务端代码(5-1)

package mytest.htmlSet;

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

/**
 * @Author: ${user}
 */
public class ServiceNew {
    public static void main(String[] args) throws IOException {
        //创建ServiceSocket类,并设置端口号为1004
        ServerSocket ss = new ServerSocket(1004);
        //接受来自浏览器的信息
        Socket accept = ss.accept();
        //返回服务器的一个输入流
        InputStream is = accept.getInputStream();
        //翻译来自浏览器的请求并打印在控制台
        int len ;
        byte[] bytes = new byte[1024];
        while ((len=is.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }
    }
}

运行服务器代码,并在浏览器中输入以下网址:

http://127.0.0.1:1004/

注:127.0.0.1是本地网址,1004是服务端口号,这个端口号在创建ServiceScoket对象时已经设置,当输入网址并点击确认后,浏览器会自动定位到127.0.0.1(本地)的ServiceNew中。而服务器端代码会在在控制台打印下面的内容,一下内容就是浏览器向服务器发送的信息。为了方便解读,我将每行信息前标注了序号。

1、GET / HTTP/1.1
2、Host: 127.0.0.1:1004
3、Connection: keep-alive
4、Cache-Control: max-age=0
5、Upgrade-Insecure-Requests: 1
6、User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
7、Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
8、Accept-Encoding: gzip, deflate, br
9、Accept-Language: zh-CN,zh;q=0.9
 

 第一行:GET / HTTP/1.1  这一行有三个信息。GET是浏览器以何种方式访问,有GET和POST之分,紧接着的 “/” 这个符号其实是l路径分隔符,单个的路径分隔符就是根目录的意思,HTTP/1.1是超文本传输协议,每个网站都要遵守的协议。总的来说这一行,浏览器告诉服务器的信息是,“我”(浏览器)要以GET的方式,在按照HTTP/1.1协议的情况下,访问你服务器根目录的空文件。如果将原本的网址写成http://127.0.0.1:1004/web,此时的第一行就会变成GET /web HTTP/1.1 。

第二行:是访问的服务号和端口号

后面几行都是浏览器信息和和访问的要求,在这里不再赘述!

其实分析到这,如果服务器获取浏览器发送的请求信息中的第一行,获取,浏览器要访问的路径,就可以把服务器上的信息回写出去。获取浏览器发送的信息的第一行,可以使用BufferReader的readLine方法获取,然后进行切割,从而获取浏览器要访问的内容的路径。

 给浏览器回写内容,需要在服务器代码中写下如下代码。告诉浏览器访问成功了,我将以文本形式输出。

os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
os.write("\r\n".getBytes());

我们先试着在浏览器返回一段话:

package mytest.htmlSet;

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

/**
 * @Author: ${user}
 */
public class ServiceNew {
    public static void main(String[] args) throws IOException {
        //创建ServiceSocket类,并设置端口号为1004
        ServerSocket ss = new ServerSocket(1004);
        //接受来自浏览器的信息
        Socket accept = ss.accept();
        //返回服务器的一个输入流
        InputStream is = accept.getInputStream();
        //翻译来自浏览器的请求并打印在控制台
        int len ;
        byte[] bytes = new byte[1024];
//        while ((len=is.read(bytes))!=-1){
//            System.out.println(new String(bytes,0,len));
//        }
        len = is.read(bytes);
        System.out.println(new String(bytes));

        OutputStream os = accept.getOutputStream();
        os.write("HTTP/1.1 200 OK\r\n".getBytes());
        os.write("Content-Type:text/html\r\n".getBytes());
//        os.write("Accept-Language:UTF-8".getBytes());
        os.write("\r\n".getBytes());

        os.write("啥?".getBytes());
    }
}

在浏览器输入网址和端口号后成功显示“啥?”

接下来我们就动手完成B\S服务器的代码

package mytest.htmlSet;

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

/**
 * @Author: ${user}
 */
public class ServiceNew {
    public static void main(String[] args) throws IOException {
        //创建ServiceSocket类,并设置端口号为1004
        ServerSocket ss = new ServerSocket(1004);
//创建无限循环,重复开启线程获取图片信息
        while (true) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //接受来自浏览器的信息
                        Socket accept = ss.accept();
                        //返回服务器的一个输入流
                        InputStream is = accept.getInputStream();
                        // 创建BufferedReader并调用readLine方法获取浏览器请求的第一行
                        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        String s = br.readLine();
//        System.out.println(s);
                        //调用String的split方法分隔获取到的第一行的数据返回一个数组,并获取第二个元素,并去掉第一个路径分隔符
                        String s1 = s.split(" ")[1].substring(1);
                        System.out.println(s1);
                        //创建File对象指向浏览器要访问的路径
                        File file = new File(s1);
                        //判断是否存在---测试
                        System.out.println(file.exists());
                        //创建缓冲流对象,读取路径下下的信息
                        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                        //获取输出流对象,把路径下的内容写回去
                        OutputStream os = accept.getOutputStream();
                        os.write("HTTP/1.1 200 OK\r\n".getBytes());
                        os.write("Content-Type:text/html\r\n".getBytes());
                        os.write("\r\n".getBytes());
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while ((len = bis.read(bytes)) != -1) {
                            os.write(bytes, 0, len);
                        }
                        //关闭资源
                        os.close();
                        bis.close();
                        br.close();
                        is.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }


    }


}

在浏览器输入http://127.0.0.1:1004/tes_net/web/index.html,即可访问web项目

总结:

能力尚浅,有待进步,如有不足,不吝赐教!

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值