【JAVADAY23】反思socket与线程

关于socket与线程

1、如果你有一个服务端A,端口是8888

2、如果你有5个不同的电脑,同时来访问服务端A,访问端口是8888,ip是本机ip

你会发现你在服务端接收到的每个socket对象都是不同的,因为每个主机的ip地址不同,即使是你用同一台电脑开5个同样的Java程序,去请求服务端A的8888端口,你会发现socket仍然是不同的,因为每个Java程序在访问时提供的自己的端口是不同的,不可能一个端口供2个Java程序使用。

我们为什么要把socket与线程连在一起?

在显示生活中,一个服务端,它肯定是一直开着的,不论何时他都在不断的监听有无客户端访问,因此一般来说服务端A的aceept.serversocket我们是放在while循环中的,目的就是为了让它模拟现实状态,但我们监听后,获得的这些socket对象做什么呢?我们是用来读取数据的,那为什么不直接在while中写它的具体操作呢,何必在与线程绑在一起呢?答案是显而易见的,如果我们在while中去实现每个socket要做的事情,你会遇到一个问题,当一个客户端B1在访问服务端A的时候,如果它连接上去后什么都不做,那么当客户端B2再访问服务端A的时候,就会出现一种类似死锁的状态,即B1占用资源却什么也不做,服务端A无可奈何。

**线程就很好的解决了这一现象,因为线程是可以并发的,我们的服务端A在接受到客户端B1的请求时,生成的socket对象我们可以放在继承了Thread的类的对象中,注意这个socket是服务器的,它的作用是与客户端的socekt连接,当前前提是你要在该类声明一个socket的变量,以及一个构造器。我们就创建了一个线程,就可以让每个客户端在自己的线程内做事,而不必一直占用与服务端连接的那一条线程,服务端的线程仅用来接受每个客户端的socket对象,并把他们放在每个线程中,这个过程是很迅速的。当然,不要忘了要start启动线程,否则就仅仅只是一个socket绑定一个线程,啥事也不做。**在服务器的java程序里,如果你想一直读取客户端发来的数据,就需要在此基础上在run方法中,使用socket的input或者output.

客户端同样是这样,服务端就是一个特殊的客户端。如果你客户端run方法是while语句,就可以做到让socket一直读取服务端的信息和一直接收服务端的信息,说白了就是可以让客户端B1一直与服务端A通信。只要你的B1客户端一直在就能保持一直通信,为啥呢,因为在最开始的时候你已经与服务端建立连接了,服务端那边收到了你的请求,根据你的ip/端口创建了一个socket对象,只要这个对象在,你俩就一直是在连接着的。

客户端B1的socket如果编号是1的话,服务端其中一个socket的编号就是1,它俩一一对应

客户端B2的socket如果编号是2的话,服务端其中一个socket的编号就是2,它俩一一对应

客户端:Socket[addr=TMJIE5200/192.168.129.1,port=7777,localport=62754]
服务端:sockte名为:Socket[addr=/192.168.129.1,port=62754,localport=7777]正在执行!!
可见两者的socket是一一对应的 都是id 62754 

run方法,如果是while,只要启动了它就是一直执行的,因为是线程它会与main线程同时执行,所以run方法的作用就是在后台不断的读、写数据。只不过没有输出语句你看不到罢了。

注意:传入的socket不同,因此必须每传入一个就启动一下。因此一般 构建对象,与启动线程是放在while中的

while (true) {
    //每个程序生成的client是不同的,即使是同一台电脑会由于不同的端口号而不同
    //因为一个端口号被占用后就只能用另外一个了
    //你每一个要访问服务端的,都会获得一个不同的进程,因为client不同,而我的构造器需要的恰好是client
    //因此每个client的线程是不同的
    //因此你可以实现每一个线程绑定一个client对象
    /*
        Socket[addr=TMJIE5200/192.168.129.1,port=7777,localport=61873]
        0
        2
        Socket[addr=TMJIE5200/192.168.129.1,port=7777,localport=61882]
        0
        3
        Socket[addr=TMJIE5200/192.168.129.1,port=7777,localport=61891]
        0
        4
        Socket[addr=TMJIE5200/192.168.129.1,port=7777,localport=61896]
        0
        5
        Socket[addr=TMJIE5200/192.168.129.1,port=7777,localport=61902]
        0
    * */
    Server001是继承了Thread的类,因此可以直接调用start方法
    Socket client = serverSocket.accept();
    //-------------程序会一直client卡在那里,没有while执行一次就不接受了---------
    Server001 server001 = new Server001(client);
    //接受的对象不同,每次都要启动一下,放在后台
    server001.start();
    System.out.println(i++);
}

但正常来说客户端就就不需要,因为客户端就只有你一个人在使用,你启动一次就行了

服务端是每来一个就启动一个线程放在后台

每个客户端都可以做自己的事情,而不必导致一个占用资源, 其他人只能干等着。

下面是我的继承了Thread类的内容

private Socket client;
public Server001(Socket i) {
    client=i;
}
@Override
public void run() {
    int i=0;
    try {
        while (true) {//true 保证一直在后台运行
            InputStream inputStream = client.getInputStream();
            //下面这是一个转接流 字节转字符
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String s = bufferedReader.readLine();
            System.out.println(s);
            client.shutdownInput();
            System.out.println(i);
            client.close();
            return;
            //System.out.println("哇哇哇哇" + Server001.currentThread());
        }
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }

3、 管理线程,如果客户端B1向客户端B2发送信息,它就必须经过服务端,服务端很容易知道是谁发的,但是怎么才能让服务端找到与客户端B2连接的线程呢,因为线程找到了与B2连接的socket就找到了,就可以写数据了,一般是创建一个hashmap来存储。通过传来的id获取对应的线程。

4、关于流

output流是从程序读到程序

input是从程序读到某个地方

就是说它并不是直接写到你的文件夹中或者客户端中,而是写到程序中,你调用input在从程序中读到某个文件夹

在网络编程中

服务端发了一条消息给客户端,客户端是没法直接显示的,因为这条消息此时在程序中,你想要读就要使用inputstream从程序中读,写是同样的,从服务端写,写到客户端的程序中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Keyle777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值