使用Socket构建简易聊天室

来源:互联网 发布:模拟退火算法简单实例 编辑:程序博客网 时间:2024/05/22 05:29

Socket,简称套接字,由ip和port(端口号组成),例如:192.168.1.16:8080,Socket有两种主要的操作方式:面向连接的和无连接的,即TCP和UDP连接,面向连接的使用TCP协议。

Java在包Java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端,服务器端先通过ServerSocket开启服务,然后客户端才可通过新建一个Socket连接到服务器端。

首先先看一下服务器端的构建

这里通过Java代码实现服务器端的功能:

import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;public class MyServer {// 定义保存所有Socket的集合  public static ArrayList<Socket> sockets = new ArrayList<Socket>();public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(20000);System.out.println("服务器创建成功");System.out.println("等待客户端的连接.....");while (true) {Socket socket = serverSocket.accept();System.out.println("有客户端链接进来");sockets.add(socket);new Thread(new ServerThread(socket)).start();}}}
服务器端线程代码:

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import java.net.Socket;public class ServerThread implements Runnable {// 定义当前线程所处理的Socketprivate Socket socket = null;// 该线程所处理的Socket所对应的输入流BufferedReader br = null;public ServerThread(Socket socket) throws UnsupportedEncodingException,IOException {this.socket = socket;// 初始化该Socket对应的输入流br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));}OutputStream os;@Overridepublic void run() {try {String content = null;// 采用循环不断从Socket中读取客户端发送过来的数据while ((content = readFromClient()) != null) {// 遍历socketList中的每个Socket,将读到的内容向每个Socket发送一次for (Socket s : MyServer.sockets) {os = s.getOutputStream();os.write((content + "\n").getBytes("utf-8"));String ss = MyServer.sockets.toString();System.out.println(ss);}}} catch (Exception e) {e.printStackTrace();}}/** * 定义读取客户端数据的方法 *  * @return */private String readFromClient() {try {return br.readLine();}// 如果捕捉到异常,表明该Socket对应的客户端已经关闭catch (Exception e) {// 删除该Socket// MyServer.sockets.remove(socket);e.printStackTrace();}return null;}}
创建好服务器端Java项目之后,再新建一个Android项目来创建客户端

客户端的代码实现如下:

import java.io.OutputStream;import java.net.Socket;import android.app.Activity;import android.content.Context;import android.net.wifi.WifiInfo;import android.net.wifi.WifiManager;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;public class MainActivity extends Activity {private EditText input;private EditText show;private Button sendBtn;private OutputStream os;private Handler handler;private Button main_btn_refresh;private String ip;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);input = (EditText) findViewById(R.id.main_et_input);show = (EditText) findViewById(R.id.main_et_show);sendBtn = (Button) findViewById(R.id.main_btn_send);main_btn_refresh = (Button) findViewById(R.id.main_btn_refresh);main_btn_refresh.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {getConnect();}});handler = new Handler() {@Overridepublic void handleMessage(Message msg) {// 如果消息来自子线程if (msg.what == 0x234) {// 将读取的内容追加显示在文本框中show.append("\n" + msg.obj.toString());}}};getConnect();ip = getIp();sendBtn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {try {// 将用户在文本框内输入的内容写入网络os.write((ip + ":     " + input.getText().toString() + "\r\n").getBytes());// 清空input文本框数据input.setText("");} catch (Exception e) {e.printStackTrace();}}});}// 开启链接服务private void getConnect() {new Thread() {public void run() {Socket socket;try {Log.i("开启客户端请求", "请求打开");socket = new Socket("192.168.1.67", 20000);// 客户端启动ClientThread线程不断读取来自服务器的数据new Thread(new ClientThread(socket, handler)).start();os = socket.getOutputStream();} catch (Exception e) {e.printStackTrace();}};}.start();}public String getIp() {// 获取wifi服务WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);// 判断wifi是否开启if (!wifiManager.isWifiEnabled()) {wifiManager.setWifiEnabled(true);}WifiInfo wifiInfo = wifiManager.getConnectionInfo();int ipAddress = wifiInfo.getIpAddress();String ip = intToIp(ipAddress);return ip;}private String intToIp(int i) {return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF)+ "." + (i >> 24 & 0xFF);}}
客户端线程实现:

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;import android.os.Handler;import android.os.Message;public class ClientThread implements Runnable {private Handler handler;// 该线程所处理的Socket所对应的输入流private BufferedReader br = null;public ClientThread(Socket socket, Handler handler) throws IOException {this.handler = handler;br = new BufferedReader(new InputStreamReader(socket.getInputStream()));}@Overridepublic void run() {try {String content = null;// 不断读取Socket输入流的内容while ((content = br.readLine()) != null) {// 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据Message msg = new Message();msg.what = 0x234;msg.obj = content;handler.sendMessage(msg);}br.close();} catch (Exception e) {e.printStackTrace();}}}
Activity的布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="${relativePackage}.${activityClass}" >    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="horizontal" >        <EditText            android:id="@+id/main_et_input"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="10" />        <Button            android:id="@+id/main_btn_send"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:text="发送" />        <Button            android:id="@+id/main_btn_refresh"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:text="重新连接" />    </LinearLayout>    <EditText        android:id="@+id/main_et_show"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:cursorVisible="false"        android:editable="false"        android:gravity="top" /></LinearLayout>
最后在清单文件中加入下面的权限:

   <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >    </uses-permission>    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >    </uses-permission>    <uses-permission android:name="android.permission.WAKE_LOCK" >    </uses-permission>
之后在两个客户端进行对话,
产生了下面的效果:







本文转载自:http://blog.csdn.net/u010142437/article/details/9327541

0 0
原创粉丝点击