进程间通信---Socket

Socket

  概念

      socket俗称“套接字”,是网络通信中的概念,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远程主机的IP地址,远程进程的协议端口。它分为流式套接字和用户数据报套接字两种,分别对应于网络的传输控制层的TCP和UDP协议。

  作用

     能够唯一标识网络中的进程,进行进程间通信。比如:两个进程(程序)进行通讯最基本的一个前提能够有唯一的标识,在本地进程通讯中我们可以使用PID来唯一标识一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,但是我们知道ip地址可以标识主机,而TCP层协议和端口号可以唯一标识主机的一个进程,这样我们可以利用ip地址,协议,端口号唯一标识网络中的一个进程。

    用法

客户端

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final int MESSAGE_RECEIVE_NEW_MSG = 1;
    private static final int MESSAGE_SOCKET_CONNECTED = 2;
    private Button mSendButton;
    private TextView mMessageTextView;
    private EditText mMessageEditText;
    private PrintWriter mPrintWriter;
    private Socket mClientSocket;
    private Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case MESSAGE_RECEIVE_NEW_MSG:
                    mMessageTextView.setText(mMessageTextView.getText()+(String)msg.obj);
                    break;
                case MESSAGE_SOCKET_CONNECTED:
                    mSendButton.setEnabled(true);
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMessageTextView = (TextView) findViewById(R.id.msg_container);
        mSendButton = (Button) findViewById(R.id.send);
        mSendButton.setOnClickListener(this);
        mMessageEditText = (EditText) findViewById(R.id.msg);
        Intent intent = new Intent(this,TcpServerService.class);
        startService(intent);
        new Thread(){
            @Override
            public void run() {
                super.run();
                //开启一个子线程,连接服务端
                connectTcpServer();
            }
        }.start();
    }
    //格式化时间
    private String formatDataTime(long time){
        return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
    }
    private void connectTcpServer() {
        Socket socket=null;
        while(socket==null){
            try {
                socket=new Socket("localhost",8688);
                mClientSocket=socket;
                mPrintWriter=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
                //当连接服务器端成功时,发送按钮是可以点的
                mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
                System.out.println("connect server success");
            } catch (IOException e) {
                SystemClock.sleep(1000);
                System.out.println("connect faild.....");
            }
        }
        try {
            //接收服务器端的消息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (!MainActivity.this.isFinishing()){
                String msg = br.readLine();
                System.out.println("receive :"+msg);
                if(msg !=null){
                    String time=formatDataTime(System.currentTimeMillis());
                    final String showedMsg ="server " + time + ":" + msg
                            + "\n";
                    //服务端发来消息后,发到主线程,显示界面上。
                    mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG,showedMsg).sendToTarget();
                }
            }
            System.out.println("quit...");
            MyUtils.close(mPrintWriter);
            MyUtils.close(br);
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onClick(View v) {
        if (v == mSendButton) {
            final String msg = mMessageEditText.getText().toString();
            if (!TextUtils.isEmpty(msg) && mPrintWriter != null) {
                mPrintWriter.println(msg);
                mMessageEditText.setText("");
                String time = formatDataTime(System.currentTimeMillis());
                final String showedMsg = "self " + time + ":" + msg + "\n";
                mMessageTextView.setText(mMessageTextView.getText() + showedMsg);
            }
        }
    }
    @Override
    protected void onDestroy() {
        //退出界面时,关闭socket
        if (mClientSocket != null) {
            try {
                mClientSocket.shutdownInput();
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }
}
服务端

public class TcpServerService extends Service {
    private boolean mIsServiceDestoryed = false;
    private String[] mDefinedMessages = new String[] {
            "你好,亲",
            "请问你叫什么名字呀?",
            "今天北京天气怎么样啊。。。",
            "你知道吗?我可是可以和多个人同时聊天的哦",
            "给你讲个笑话吧:据说爱笑的人运气不会太差,不知道真假。"
    };
    public TcpServerService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public void onCreate() {
        new Thread(new TcpServer()).start();
        super.onCreate();
    }
    @Override
    public void onDestroy() {
        mIsServiceDestoryed=true;
        super.onDestroy();
    }
    private class TcpServer implements  Runnable{
        @Override
        public void run() {
            ServerSocket serverSocket=null;
            try {
                serverSocket=new ServerSocket(8688);
            }catch (Exception e){
                System.out.println("建立tcp 服务端连接失败,端口:8688");
                e.printStackTrace();
            }
            while(!mIsServiceDestoryed){
                try {
                    //接受客户端请求
                    final Socket client = serverSocket.accept();
                    System.out.println("accept");
                    new Thread(){
                        @Override
                        public void run() {
                            super.run();
                            try {
                                responseClient(client);
                            }catch (IOException e){
                                e.printStackTrace();
                            }
                        };
                    }.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    private void responseClient(Socket client) throws IOException{
        //用于接收客户端消息
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        //用于向客户端发送消息
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
        out.println("欢迎来到聊天室。。。");
        while(!mIsServiceDestoryed){
            String str = in.readLine();
            System.out.println("消息来自客户端:"+str);
            if(str==null){
                break;
            }
            int i = new Random().nextInt(mDefinedMessages.length);
            String msg = mDefinedMessages[i];
            out.println(msg);
            System.out.println("send"+msg);
        }
        System.out.println("client quit.");
        //关闭流
        MyUtils.close(out);
        MyUtils.close(in);
        client.close();
    }
}

MyUtils

public class MyUtils {
    public static void close(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void executeInThread(Runnable runnable) {
        new Thread(runnable).start();
    }
}
运行效果


代码链接

应用场景

          socket在Android开发中不是很常用,主要是在面试的时候,常常会碰到面试题让你现场手搓一个Socket,所以下面的代码纯java的,供你面试时参考
客户端:
public class Client {
	public static void main(String[] args) throws Exception, IOException {
		Socket socket = new Socket("172.60.20.168",30000);
		//如果能够执行到这里 说明建立成功了
		//这个输入流读取客户端发送的内容
		BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf8"));
		PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
		//服务端的问候语
		String string = br.readLine();
		System.out.println(string);
		Scanner scanner = new Scanner(System.in);
		while(true)
		{
			String request=scanner.nextLine();
			pw.println(request);
			//等待服务器的相应
			String response=br.readLine();
			System.out.println(response);
			if(response.equals("bye")){
				break;
			}
		}
		br.close();
		pw.close();
		scanner.close();
		socket.close();
	}
}
服务端:
public class Server {
	ServerSocket serverSocket;
	List<Socket> sockets=new ArrayList<Socket>();
	private void start()
	{
		//具体业务逻辑
		try {
			//端口号 0--65535一般用10000-65535
			serverSocket=new ServerSocket(30000);
			System.out.println("服务器已经启动。。。。");
			//等待作为客户端socket进行连接
			while(true){
				Socket socket = serverSocket.accept();
				sockets.add(socket);
				new MyThread(socket).start();

			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//服务端要用一个单独的线程 为客户端服务
	private class MyThread extends Thread{
		Socket socket;
		public MyThread(Socket socket) {
			super();
			this.socket = socket;
		}
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			//服务端的输入流接受客户端发来的信息
			try {
				//连接已经建立起来 服务端利用上面accept方法与客户端进行通信
				//采用IO流的形式进行通信
				BufferedReader br = new BufferedReader(
						new InputStreamReader(socket.getInputStream(),
								"utf8"));
				while(true)
				{
					String request = br.readLine();
					//把客户端写入的话转发给所有socket
					for(Socket s:sockets){
						PrintWriter pw=new PrintWriter(new OutputStreamWriter(
								s.getOutputStream(), "utf8"),true);
						pw.println(request);
					}
				}
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) {
		Server server = new Server();
		server.start();
	}
}

PS:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值