JAVA Socket模拟简单通讯实例(二)

4 篇文章 0 订阅

    第一篇讲述了什么是Socket和什么是java Socket。于是就可以进行实践了。

    这个例子是一个经典的C/S模型。

    首先,我们需要一个服务器。和一个客户端。

    但是,前文讲了,socket链接是一个点对点的链接方式,并没有服务器客户端之说,产生socket链接的双方是对等的,都持有一个socket,用来建立流,产生数据交互。

    如我们创建的阻塞式的传统IO流,那么一定会发生阻塞的情况。因为一个线程执行到read()方法时,就阻塞了。那么明显的,如果我们只用一个线程作为服务器的话,是无法应对多个客户端的链接需求的。

    举个形象的例子,服务器就是一个人,客户端也是一个人。2个人通话的时候不允许干其他的事情。如果是这样的话,那么如果第一个用户一直霸占着客户端,那么下面的用户都是无法进行链接的。解决方案也很简单,现在派出一个人,作为客户分配者,类似于公司前台的存在,只负责分配任务。来一个客户,前台分配一个具体的负责人(也就是一个处理线程)给他。由这个线程与客户进行通讯,前台继续等待下一个客户的到来。


    这个例子中,有几个对象。

    前台:服务器的线程分配者 即 java.net.ServerSocket

    客户:也就是客户端:Client 自己实现

    具体的负责人:ServerClient 自己实现 。一个线程对象持有一个ServerSocket分配的Socket



    流程如下:

    服务器启动,然后阻塞,等待客户端的链接。

    客户端新建一个Socket,传入地址和端口,进行链接。

    ServerSocket接受此客户端,创建一个socket对象。

    服务器将用此socket对象创建 线程对象ServerClient

    然后服务器启动ServerClient对象,ServerSocket方法执行accpet()方法阻塞,等待下一个客户端的链接。

    代码如下 客户端:

package xin.tomdonkey.demo01;

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

public class Client
{
    Socket socket ;
    boolean flag = false;
    InputStream inputStream ;
    OutputStream outputStream ;

    public Client(String address,int port) throws IOException
    {
        this.socket = new Socket(address,port);
        this.inputStream = socket.getInputStream();
        this.outputStream = socket.getOutputStream();
    }

    public void startup() throws IOException, InterruptedException
    {
        flag = true;
        while (flag)
        {
            //由客户端发起,向服务器写出数据,一个随机byte值
            byte b = (byte)new Random().nextInt(100);
            outputStream.write(b);
            System.out.println("写出:" + b);

            //写出完成之后,线程阻塞,直到收到服务器发来的值为止
            int r = inputStream.read();
            System.out.println("收到:" + r);
            System.out.println("完成一次请求\n");

            //收到之后线程休眠2s,再向服务器写出数据
            Thread.sleep(2000);
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException
    {
        Client client = new Client("127.0.0.1",6655);
        client.startup();
    }
}
服务器:一个线程分配器
package xin.tomdonkey.demo01;

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

public class Server
{
    int port = 6655;
    boolean flag = false;
    ServerSocket serverSocket ;

    /**
     * 采用默认端口6655创建服务器
     * @throws IOException
     */
    public Server() throws IOException
    {
        this.serverSocket = new ServerSocket(port);
    }

    /**
     * 指定端口port创建服务器
     * @param port 服务器监听的端口
     * @throws IOException
     */
    public Server(int port) throws IOException
    {
        this.port = port;
        this.serverSocket = new ServerSocket(port);
    }

    /**
     * 启动服务器,进行监听和分配线程操作。
     * 此方法会将服务器的状态变更为启动,即flag = true
     * @throws IOException
     */
    public void startUp() throws IOException
    {
        flag = true;
        while (flag)
        {
            Socket socket = serverSocket.accept();
            Thread serverClientThread = new Thread(new ServerClient(socket));
            serverClientThread.start();
        }
    }


    public static void main(String[] args) throws IOException
    {
        new Server().startUp();
    }
}

服务器线程对象:进行具体通讯的线程对象

package xin.tomdonkey.demo01;

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

/**
 * 用来处理每一个连接的线程类。
 * 每一个客户端的链接都会由Server分配一个此类的线程对象进行处理。
 */
public class ServerClient implements Runnable
{
    Socket socket ;
    InputStream inputStream ;
    OutputStream outputStream ;

    /**
     * 由Server创建,传入socket进行处理。
     * @param socket
     * @throws IOException
     */
    public ServerClient(Socket socket) throws IOException
    {
        this.socket = socket;
        this.inputStream = socket.getInputStream();
        this.outputStream = socket.getOutputStream();
    }


    @Override
    public void run()
    {
        while (true)
        {
            try
            {
                //线程启动,即阻塞,直到客户端发出数据
                //可以做一个优化,收不到数据即销毁当前线程以及链接和流
                int  r= inputStream.read();
                System.out.println("收到:" + r);

                //收到后即回复给客户端一个随机值
                byte b = (byte)new Random().nextInt(100);
                outputStream.write(b);
                System.out.println("写出:" + b);

                System.out.println("完成一次回复\n");
            }
            catch (IOException e)
            {
                //客户端掉线了 抛出此异常
                e.printStackTrace();
            }
        }
    }
}

注:基础版本v1.0

[简介]
启动Server之后
启动Client
client会自动向Server发出一次请求,每隔2s请求一次,
此版本不讨论服务器异常问题,写入操作执行完成之后,即阻塞,等待回复

[待解决问题]
异常基本都为抛出操作
采用基础阻塞式io
不添加缓冲区操作
不添加销毁回收操作
每次传输都传输一个随机的byte值



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值