刚开始接触Android的网络通信开发。
目前自己写了一个聊天室的小程序,记录一下。
本程序包括:
1.服务器:由java开发
2.客户端:由Android开发
服务器的console起到接受并且转发的目的:
服务端代码:
package com.ustclin.talk;
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.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
//private static final String IP_ADDRESS = "192.168.0.200";
private static final int PORT = 18888;
private static int num = 0;
public static ArrayList socketList = new ArrayList();
/**
* @param args
*/
public static void main(String[] args) {
ServerSocket serverSocket = null;
System.out.println("ServerSocket Begin........");
try {
serverSocket = new ServerSocket(PORT);
// 使用循环方式一直等待客户端的连接
while (true) {
num++;
Socket accept = serverSocket.accept();
socketList.add(accept);
System.out.println("arrayList num = "+socketList.size());
// 启动一个新的线程,接管与当前客户端的交互会话
new Thread(new ServerThread(accept , "Client "+num ), "Client " + num).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
System.out.println("----> serverSocket closed.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* @author JCC 服务器处理客户端会话的线程
*/
class ServerThread implements Runnable {
Socket socket = null;
String clientName = null;
public ServerThread(Socket socket , String clientName) {
System.out.println("Create a new ServerThread...");
this.socket = socket;
this.clientName = clientName;
}
@Override
public void run() {
try {
// 接收客户端消息
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String message = null;
if (!socket.isClosed()) {
try {
message = in.readLine();
} catch (Exception e) {
e.printStackTrace();
}
if(null == message){
// the socket is null , means that the client is disconnect
Server.socketList.remove(socket);
break;
}
System.out.println("server read Line from "+ clientName + " success! message = " + message);
for(Socket ss : Server.socketList){
// 发送消息,向客户端
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(ss.getOutputStream())), true);
out.println(this.clientName +": "+ message);
System.out.println("Thread " + clientName + " socket send out");
}
}
}
}
catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("out of while");
}
}
}
interface Constant {
public static final String SERVER_IP = "192.168.0.200";
public static final int PORT = 19999;
}
客户端主程序:
package com.ustc.linkun.chat;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG = "ConnectToServer";
private static final String CONNECTED = "connected ! ";
private static final String CONNECTINGSERVER = "connecting ...";
private TextView tvForIpAddress;
private TextView tvForPort;
private EditText mIpAddress;
private EditText mPort;
private Button mConnect;
private TextView mServerMsg;
private EditText editText;
private Button button1;
private static final int SEND_DATA = 0;
private static final int GET_DATA_FROM_SERVER = 1;
private static final int CONNECT_TO_SERVER = 2;
private static final int CONNECTING = 3;
private MyHandler myHandler;
private Socket socket = null;
private Context mContext;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this;
tvForIpAddress = (TextView) findViewById(R.id.tvForIpAddress);
tvForPort = (TextView) findViewById(R.id.tvForPort);
mIpAddress = (EditText)findViewById(R.id.ipAddress);
mPort = (EditText) findViewById(R.id.port);
mConnect = (Button) findViewById(R.id.connect);
editText = (EditText) findViewById(R.id.editText1);
mServerMsg = (TextView) findViewById(R.id.serverMsg);
//mServerMsg.setEnabled(false);
button1 = (Button) findViewById(R.id.button1);
myHandler = new MyHandler();
mConnect.setOnClickListener(this);
button1.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
// connect server
case R.id.connect:
// connecting , avoid multi button click which can result sending multi-connect request
Runnable r0 = new Runnable() {
@Override
public void run() {
Message msg = myHandler.obtainMessage();
msg.what = CONNECTING;
myHandler.sendMessage(msg);
}
};
new Thread(r0).start();
// use for connection
Runnable r1 = new Runnable() {
@Override
public void run() {
initSocket();
ClientThread ct = new ClientThread(socket , "Client");
new Thread(ct).start();
//connectToServer(mIpAddress.getText().toString(), Integer.parseInt(mPort.getText().toString()));
if(socket.isConnected()){
Message msg = myHandler.obtainMessage();
msg.what = CONNECT_TO_SERVER;
myHandler.sendMessage(msg);
}
}
};
new Thread(r1).start();
break;
// send data
case R.id.button1:
Runnable r2 = new Runnable() {
@Override
public void run() {
Message msg = myHandler.obtainMessage();
String str = editText.getText().toString();
System.out.println(">>>>editText: " +str);
Bundle bundle = new Bundle();
bundle.putString("content", str);
msg.what = SEND_DATA;
msg.setData(bundle);
myHandler.sendMessage(msg);
}
};
new Thread(r2).start();
break;
default:
break;
}
}
private void initSocket() {
try{
//socket = new Socket(ipAddress , port);
socket = new Socket(mIpAddress.getText().toString(),Integer.parseInt(mPort.getText().toString()));
socket.setKeepAlive(true);
socket.setSoTimeout(10 * 60 * 1000);
} catch (Exception e){
e.printStackTrace();
}
}
//private class
private class MyHandler extends Handler {
public MyHandler() {
}
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case SEND_DATA:
//Bundle bundle = new Bundle();
final String str = (String)msg.getData().get("content");
System.out.println(">>>>>content : " + str);
if(str.equals("")){
Toast.makeText(mContext,"不能发送空内容!",Toast.LENGTH_SHORT).show();
}
else {
new Thread(new Runnable() {
@Override
public void run() {
sendData(str);
}
}).start();
editText.setText("");
//mServerMsg.append(str);
}
break;
case GET_DATA_FROM_SERVER:
String str1 = (String) msg.getData().get("content");
System.out.println("myHandler get str = " + str1);
mServerMsg.append("\n"+str1);
case CONNECT_TO_SERVER:
mIpAddress.setEnabled(false);
mPort.setEnabled(false);
mConnect.setText(CONNECTED);
tvForIpAddress.setVisibility(View.GONE);
tvForPort.setVisibility(View.GONE);
mIpAddress.setVisibility(View.GONE);
mPort.setVisibility(View.GONE);
mConnect.setVisibility(View.GONE);
//mServerMsg.setText("The Server is connected!");
case CONNECTING:
mConnect.setText(CONNECTINGSERVER);
mConnect.setEnabled(false);
default:
break;
}
}
}
// send data
private void sendData(String content) {
// server is on
try {
//String content = editText.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter
(socket.getOutputStream())), true);
//发送数据
out.println(content);
System.out.println(">>>>>send out SUCCESSFUL!");
} catch (Exception e) {
e.printStackTrace();
}
}
//
private void send_CONNECTION_CLOSE_DATA(){
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter
(socket.getOutputStream())), true);
//发送数据
out.println("closing-connection");
System.out.println("closing-connection");
} catch (Exception e){
e.printStackTrace();
}
}
// close the connection to the server
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (null != socket) {
new Thread(new Runnable() {
@Override
public void run() {
send_CONNECTION_CLOSE_DATA();
}
});
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private class ClientThread implements Runnable{
private Socket socket = null;
private String name;
public ClientThread(Socket socket , String threadName){
this.socket = socket;
this.name = threadName;
}
@Override
public void run() {
try {
// 接收客户端消息
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String message = null;
try {
if (!socket.isClosed()) {
message = in.readLine();
System.out.println("Server:" + message);
Message msg = myHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("content" , message);
msg.setData(b);
msg.what = GET_DATA_FROM_SERVER;
myHandler.sendMessage(msg);
System.out.println("read Line success! message = " + message);
}
Thread.sleep(1000);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//in = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端界面布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/tvForIpAddress"
android:text="IP Address: " />
<EditText
android:id="@+id/ipAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="input the ip address here"
android:text="192.168.0.200">
EditText>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/tvForPort"
android:text="port: " />
<EditText
android:id="@+id/port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="input the port number here"
android:text="18888">
EditText>
<Button
android:id="@+id/connect"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="connect">
Button>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="----Talk----" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/serverMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is for TALK History zone" />
RelativeLayout>
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="">
EditText>
<Button
android:id="@+id/button1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="send">
Button>
LinearLayout>
先运行Server.java , 保证服务器在客户端之前开启
客户端是用Android Studio开发的,可以直接导入。如果你的IDE是ADT,
则可以选择性得添加里边的MainActivity.java 和 main.xml布局文件。需要
注意的是,AndroidManifest.xml文件需要添加访问INTERNET的权限
运行多个客户端,配置好服务器的IP地址后,即可进行聊天。
具体的源码大家可以去看看:基于socket的Android聊天程序