概述

Socket也称为“套接字”,是网络通信中的概念,它分为流式套接字和用户数举报套接字两种,分别对应于网络的传输控制层中的TCP和UDP协议。TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的简历需要经过”三次握手”才能完成为了提供稳定的数据传输功能,其本身提供了超时重传机制,因此具有很高的稳定性;而UDP是无连接的,提供不稳定的单向通信,当然UDP也可以实现双向通信功能。在性能上,UDP具有更好的效率,其缺点是不能保证数据一定能够正确传输,尤其是在网络拥塞的情况下。今天我们来演示一个跨进程的聊天程序,两个进程通过Socket实现信息的传输。

效果图

Socket实现进程间通信_客户端

代码

我们先看服务端的代码

public class TCPServerService extends Service {

private boolean mIsServiceDestoryed = false;
private String[] mDefinedMessages = {"你好啊","你叫什么名字","今天天气不错","给你讲个笑话"};
@Override
public void onCreate() {
super.onCreate();
new Thread(new TcpServer()).start();
}

@Override
public void onDestroy() {
super.onDestroy();
mIsServiceDestoryed = true;
}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
private class TcpServer implements Runnable{

private ServerSocket serverSocket;
private Socket client;

@Override
public void run() {
try {
//服务端Socket对象
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
e.printStackTrace();
return;
}
while ((!mIsServiceDestoryed)){
try {
//不断监听客户端的请求,请求接收成功的话返回一个代表连接的对象
client = serverSocket.accept();
new Thread(){
@Override
public void run() {
super.run();
try {
responseClient(client);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public 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();
if(str == null){
//客户端断开连接
break;
}
int i = new Random().nextInt(mDefinedMessages.length);
String msg = mDefinedMessages[i];
out.println(msg);
}
out.close();
in.close();
client.close();
}
}

接下来是客户端代码

public class MainActivity extends AppCompatActivity{
public static final int MSG_RECEIVE_NEW_MSG = 1;
public static final int MSG_SOCKET_CONNECT = 2;
private TextView tvMessage;
private Socket socket;
private EditText etMessage;

private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MSG_SOCKET_CONNECT:
btn.setEnabled(true);
break;
case MSG_RECEIVE_NEW_MSG:
tvMessage.setText(tvMessage.getText()+(String)msg.obj);
break;
}
}
};
private Button btn;
private PrintWriter out;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvMessage = (TextView) findViewById(R.id.tv_message);
etMessage = (EditText) findViewById(R.id.et_message);
btn = (Button) findViewById(R.id.btn);
Intent intent = new Intent(this,TCPServerService.class);
startService(intent);
new Thread(){
@Override
public void run() {
super.run();
connectToTcpServer();
}
}.start();
}
public void click(View view){
String content = etMessage.getText().toString();
if(!TextUtils.isEmpty(content)&&out!=null){
out.println(content);
etMessage.setText("");
String time = formatDateTime(System.currentTimeMillis());
String msg = "client"+time+":"+content+"\n";
tvMessage.setText(tvMessage.getText()+msg);
}
}

public void connectToTcpServer(){
while ((socket == null)) {
try {
socket = new Socket("localhost", 8688);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
handler.sendEmptyMessage(MSG_SOCKET_CONNECT);
}catch(IOException e){
e.printStackTrace();
}
}
//接受服务端消息
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!MainActivity.this.isFinishing()){
String str = in.readLine();
if(str!=null){
String time = formatDateTime(System.currentTimeMillis());
String msg = "server"+time+str+"\n";
handler.obtainMessage(MSG_RECEIVE_NEW_MSG,msg).sendToTarget();
}
}
in.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
protected void onDestroy() {
super.onDestroy();
if(socket!=null){
try {
socket.shutdownInput();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String formatDateTime(long time){
return new SimpleDateFormat("(HH:MM:ss)").format(new Date(time));
}
}

最后我们总结一下使用Socket通信的过程:
服务端:
1.使用端口号创建一个ServerSocket对象
2.调用accept函数监听客户端请求

客户端:
使用主机名和端口号创建一个Socket对象,注意这个端口号要和服务器的一致,不然无法建立连接