程序包括两部分,一部分是Java Socket服务器端, 一部分是Android客户端, 代码部分参考网络上的Java Socket网络编程的代码, 并已经将服务器端和客户端程序进行打包, 实现多用户的发送和接收消息功能,UI没有完善.请大家下载后观看和修改使用吧.

一, 服务器端

源码也就一个文件:  ImServer.java

package com.zhai.server;

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.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ImServer {
    private static final int PORT = 9999;// 端口监听
    private List<Socket> mList = new ArrayList<Socket>();// 存放客户端socket
    private ServerSocket server = null;
    private ExecutorService mExecutorService = null;// 线程池
    private final int POOL_SIZE = 10; // 工作线程的数目

    public ImServer() {
        try {
            server = new ServerSocket(PORT);
            // mExecutorService = Executors.newCachedThreadPool();// 创建一个线程池
            mExecutorService = Executors.newFixedThreadPool(POOL_SIZE);// 创建一个线程池

            System.out.println("Server Start…");
            Socket client = null;
            while (true) {
                client = server.accept();
                mList.add(client);
                mExecutorService.execute(new Service(client));// 开启一个客户端线程.
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new ImServer();
    }

    public class Service implements Runnable {
        private Socket socket;
        private BufferedReader in = null;
        private String msg = "";

        public Service(Socket socket) {
            this.socket = socket;
            try {
                in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream(), "utf-8"));
                msg = "user:" + this.socket.getInetAddress() + " come total:"
                        + mList.size();
                this.sendmsg();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void run() {
            // TODO Auto-generated method stub
            try {
                while (true) {
                    if ((msg = in.readLine()) != null) {
                        if (msg.equals("exit")) {
                            System.out.println("sssssssssss");
                            mList.remove(socket);
                            in.close();
                            msg = "user:" + socket.getInetAddress()
                                    + " exit total:" + mList.size();
                            socket.close();
                            this.sendmsg();
                            break;
                        } else {
                            msg = socket.getInetAddress() + " : " + msg;
                            this.sendmsg();
                        }
                    }
                }
            } catch (Exception ex) {
                System.out.println("server 读取数据异常");
                ex.printStackTrace();
            }
        }

        /**
         * 发送消息给所有客户端
         */
        public void sendmsg() {
            System.out.println(msg);
            int num = mList.size();
            for (int i = 0; i < num; i++) {
                Socket mSocket = mList.get(i);
                PrintWriter pout = null;
                try {
                    pout = new PrintWriter(new BufferedWriter(
                            new OutputStreamWriter(mSocket.getOutputStream())),
                            true);
                    pout.println(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

二,Android客户端源码

1. Mainifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zhai.im.client"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".Client"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2. main.xml

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/TextView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:singleLine="false" />

    <ListView
        android:id="@+id/server_listview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:cacheColorHint="#00000000"
        android:divider="#ffcccccc"
        android:dividerHeight="1.0px" >
    </ListView>

    <EditText
        android:id="@+id/EditText01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint=""
        android:lines="3" >
    </EditText>

    <Button
        android:id="@+id/Button02"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="发送" >
    </Button>

</LinearLayout>

3.chat_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:minHeight="40dip"
    android:orientation="vertical"
    android:paddingLeft="30dip"
    android:paddingRight="30dip" >

    <TextView
        android:id="@+id/serverlist_item_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="14dip"
        android:background="@drawable/popup_inline_error"
        >
    </TextView>

</LinearLayout>

4.Client.java

package com.zhai.im.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

public class Client extends Activity implements Runnable {
    /** Called when the activity is first created. */
    private TextView tv_msg = null;
    private EditText ed_msg = null;
    private Button btn_send = null;
    private static final String HOST = "10.2.60.20";
    private static final int PORT = 9999;
    private Socket socket = null;
    private BufferedReader in = null;
    private PrintWriter out = null;
    private String content = "";
    ListView listView;
    ChatAdapter mServerListAdapter;
    private List<String> serverlist = new ArrayList<String>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        tv_msg = (TextView) this.findViewById(R.id.TextView);
        ed_msg = (EditText) this.findViewById(R.id.EditText01);
        btn_send = (Button) this.findViewById(R.id.Button02);

        listView = (ListView) findViewById(R.id.server_listview);

        mServerListAdapter = new ChatAdapter(getApplicationContext(),
                serverlist);
        listView.setAdapter(mServerListAdapter);

        try {
            socket = new Socket(HOST, PORT);
            in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream(), "utf-8"));
            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream())), true);
        } catch (Exception ex) {
            ex.printStackTrace();
            ShowDialog("登陆异常:" + ex.getMessage());
        }
        btn_send.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                String msg = ed_msg.getText().toString();
                if (socket.isConnected()) {
                    if (!socket.isOutputShutdown()) {
                        out.println(msg);
                        ed_msg.setText("");

                    }
                }
            }
        });
        new Thread(this).start();
    }

    public void ShowDialog(String msg) {
        new AlertDialog.Builder(this).setTitle("提示").setMessage(msg)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // TODO Auto-generated method stub
                    }
                }).show();
    }

    public void run() {
        try {
            while (true) {
                if (socket.isConnected()) {
                    if (!socket.isInputShutdown()) {
                        if ((content = in.readLine()) != null) {
                            Log.i("TAG", "++ " + content);
                            content += "\n";
                            mHandler.sendMessage(mHandler.obtainMessage());
                        } else {

                        }
                    }
                }

            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.i("TAG", "– " + msg);
            // tv_msg.setText(tv_msg.getText().toString() + content);
            serverlist.add(tv_msg.getText().toString() + content);
            mServerListAdapter.notifyDataSetChanged();
            // mServerListAdapter = new ServerListAdapter(
            // getApplicationContext(), serverlist);
            // listView.setAdapter(mServerListAdapter);
        }
    };
}

5.ChatAdapter.java

package com.zhai.im.client;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ChatAdapter extends ArrayAdapter<String> {
    private Context mContext;
    private LayoutInflater inflater;

    public ChatAdapter(Context context, List<String> objects) {
        super(context, 0, objects);
        mContext = context;
        inflater = LayoutInflater.from(mContext);
        System.gc();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        String model = (String) getItem(position);

        LinearLayout view = null;
        if (convertView == null || convertView.getTag() != model) {
            final LinearLayout view1 = (LinearLayout) inflater.inflate(
                    R.layout.chat_item, null);
            view = view1;

            TextView text = (TextView) view1
                    .findViewById(R.id.serverlist_item_name);
            text.setText(model);
            // view1.initComponent(item);
            // ImageView mImageView= (ImageView
            // )view1.findViewById(R.id.themeImage);
            // mImageView.setBackgroundResource(mThemeList[position]);
            // mThemItemView.setBackgroundResource(mThemeList[position]);

            // view.setTag(model);

        } else {
            view = (LinearLayout) convertView;
        }
        view.setTag(model);

        return view;
    }

}

三, 源码打包下载

本地下载: 源码包下载(包括服务器和Android客户端的程序源码)

四, 截图

1.服务器端

server1

2.Android客户端

im1