简易TCP连接实现

5 篇文章 0 订阅
1 篇文章 0 订阅

简易TCP项目,实现小聊天室

项目结构:

TcpServer服务端代码:

package com.example.socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服务端代码
 */
public class TcpServer {
    public void start(){
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(9009);
            MsgPool.getsInstacne().start();//启动消息队列
            while (true){
                Socket socket = serverSocket.accept();//等待tcp连接到来
                System.out.println("ip="+socket.getInetAddress().getHostAddress()
                        +",port="+socket.getPort()+" is Online...");
                //避免读写操作阻塞线程,接收不到下一个连接,使用线程
//                socket.getInputStream();//客户端数据
//                socket.getOutputStream();//向客户端写数据
                ClientTask clientTask = new ClientTask(socket);
                MsgPool.getsInstacne().addMsgComingListner(clientTask);
                clientTask.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        new TcpServer().start();
    }
}

消息队列类: 

package com.example.scoket.tcp.server;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
/**
 * 消息队列,用来通知所有客户端
 */
public class MsgPool {
    /**
     * 阻塞队列
     * 1.有消息发送给队列,启动一个线程专门从队列取消息
     *
     * 2.如果队列没有消息时会阻塞
     */
    private LinkedBlockingDeque<String> mQueue = new LinkedBlockingDeque<>();

    //单例
    private MsgPool(){

    }
    private static MsgPool sInstacne = new MsgPool();

    public static MsgPool getsInstacne(){
        return sInstacne;
    }

    /**
     * 开启线程去队列读数据
     */
    public void start(){
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        String msg = mQueue.take();
                        notifyMsgComing(msg);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
    //观察者模式
    public interface MsgComingListener{
        void onMsgComing(String msg);
    }
    private List<MsgComingListener> msgComingListenerList = new ArrayList<>();
    public void addMsgComingListner(MsgComingListener listener){
        msgComingListenerList.add(listener);
    }
    private void notifyMsgComing(String msg) {
        for (MsgComingListener listener:msgComingListenerList) {
            listener.onMsgComing(msg);
        }
    }
    public void sendMsg(String msg){
        try {
            mQueue.put(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

异步任务类给客户端传消息:

package com.example.socket.tcp.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class ClientTask extends Thread implements MsgPool.MsgComingListener{
    private Socket mSocket;
    private InputStream mIs;
    private OutputStream mOs;
    public ClientTask(Socket socket){
        mSocket = socket;
        try {
            mIs = socket.getInputStream();
            mOs = socket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 此线程 客户端没有主动退出 是一直持续的
     */
    @Override
    public void run() {
        BufferedReader br = new BufferedReader(new InputStreamReader(mIs));
        String line = null;
        try {
            while ((line = br.readLine())!=null){//等待客户端发送消息,没有消息,readLine会阻塞
                System.out.println("read---"+line);
                //聊天室内,转发消息至其他客户端 并发处理 -->使用消息队列 只有一个线程去里面取数据分发数据
                MsgPool.getsInstacne().sendMsg(mSocket.getPort()+" :"+line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onMsgComing(String msg) {
        try {
            mOs.write(msg.getBytes());
            mOs.write("\n".getBytes());
            mOs.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

TCP业务类:

package com.example.socket.tcp.client;

import android.os.Handler;
import android.os.Looper;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;


public class TcpClientBiz {
    private Socket mSocket;
    private InputStream mIs;
    private OutputStream mOs;

    private Handler mUiHandler = new Handler(Looper.getMainLooper());

    public void onDestroy() {
        //多个try catch防止第一个出异常后面 的资源无法关闭
        try {
            if(mSocket!=null) {
                mSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if(mIs!=null){
                mIs.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if(mOs!=null){
                mOs.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public interface OnMsgComingListener{
        void onMsgComing(String msg);
        void onError(Exception ex);
    }
    private OnMsgComingListener mListener;
    public void setOnMsgComingListener(OnMsgComingListener listener){
        mListener = listener;
    }
    public TcpClientBiz() {
        new Thread(){//防止在ui线程作网络操作
            @Override
            public void run() {
                try {
                    mSocket = new Socket("192.168.207.2", 9009);
                    mIs = mSocket.getInputStream();
                    mOs = mSocket.getOutputStream();
                    final BufferedReader br = new BufferedReader(new InputStreamReader(mIs));
                    //循环读取服务端数据
                    String line = null;
                    while ((line = br.readLine())!=null){
                        final String finalLine = line;
                        mUiHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                if(mListener!=null){
                                    mListener.onMsgComing(finalLine);
                                }
                            }
                        });
                    }
                } catch (final IOException e) {
                    mUiHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if(mListener!=null){
                                mListener.onError(e);
                            }
                        }
                    });

                }
            }
        }.start();
    }
    public void sendMsg(final String msg){
        new Thread(){
            @Override
            public void run() {
                try {
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(mOs));
                    bw.write(msg);
                    bw.newLine();
                    bw.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

}

TCPActivity:

package com.example.socket;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.socket.Biz.UdpBiz;
import com.example.socket.tcp.client.TcpClientBiz;

public class TcpActivity extends AppCompatActivity {
    private TextView tv_result;
    private Button btn_send;
    private EditText et_input;
    private TcpClientBiz tcpBiz = new TcpClientBiz();//需优化 先loading建立连接初始化完成后再做交互
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        tcpBiz.setOnMsgComingListener(new TcpClientBiz.OnMsgComingListener() {
            @Override
            public void onMsgComing(String msg) {
                tv_result.append(msg);
            }

            @Override
            public void onError(Exception ex) {
                ex.printStackTrace();
            }
        });
    }
    private void initView(){
        tv_result = findViewById(R.id.tv_result);
        btn_send = findViewById(R.id.btn_send);
        et_input = findViewById(R.id.et_input);
        btn_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String msg = et_input.getText().toString();
                if(TextUtils.isEmpty(msg)){
                    return;
                }
                tcpBiz.sendMsg(msg);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        tcpBiz.onDestroy();//释放资源
    }
}

实现效果:

服务端----

android----

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值