android⽹络编程--Socket通信(03)点对点Android聊天室实
现(带服务器。。。
1-简介:
概念:在⽹络上的两个程序通过⼀个双向的通信连接实现数据的交换,这个双向链路的⼀端称为⼀个socket。
组成:由⼀个IP地址和⼀个端⼝号唯⼀确定,是TCP/IP 协议的⼀个⼗分流⾏的编程界⾯。
应⽤:socket编程⽐基于URL的HTTP⽹络编程提供了更⾼的传输效率、更强⼤的功能和更灵活的控制,但却复杂⼀些。
地位:socket已经是java中层次最低的⽹络编程接⼝,在java中直接操作协议中更低的层次,需要使⽤java本地⽅法调⽤(JNI)。
基础:Server端监听某个端⼝是否有连接请求,Client端向Server端发出连接请求,Server端向Client端发回Accept消息,⼀个连接就建
⽴起来了;
Server和Client端都可以⽤Send和Write等⽅法,与对⽅通信,Java在包中提供了两个类Socket和ServerSocket。
⽬前⽹上的资源⼤都⽆法实现点对点通信,要么⽤服务器⼴播,本实例将实现socket 指定的点点通信。
2-功能简介:
界⾯设计有点挫,重点在于功能,这是安卓客户端, 上⾯的 spinner下拉列表⽤来选择在线⽤户,
中间的TextView⽤于显⽰接收到的信息,(这⾥设计略简单,只做DEMO参考级别),
最下⾯输⼊聊天内容,发送按钮进⾏点对点通信。
3-服务器编程:
S1.新建⼀个java⼯程充当java 服务器,命名为ChatServer:
S2 编写服务器程序:
服务器有三个联⽹类组成:
Thread
服务线程,启动服务器时启动,开启服务ServerSocket⽤以监听端⼝收到的客户端信息。
package ;
import ption;
import Socket;
import ;
import ist;
import p;
import ;
public class ServerThread implements Runnable {
// ServerSocket 类对象
private ServerSocket rverSocket = null;
// 服务醋乳香的功效与作用点 器端⼝设置
private static final int PORT = 8888;
// 存储接收到客户端的消息
public List
// 服务器启动标志位
private boolean isStart = true;
// 存储客户端socket
// 存储客户端socket
public HashMap
/**
* 构造函数
*/
public ServerThread(){
// 初始化 message 存储list
messagelt = new ArrayList
// 初始化客户端socket
clientsMap = new HashMap
try {
// 开启服务器socket
rverSocket = new ServerSocket(PORT);
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
// 启动消息处理线程
new Thread(new MessageHandlerThread(this)).start();
}
/**
* ⼀旦有客户端连⼊,就启动客户端处理线程,并加⼊服务器客户端HashMap中
*/
@Override
public void run() {
// TODO Auto-generated method stub
while(isStart){
try {
// 获取⼀个连接客户端
Socket socket = ();
n("连⼊⼀个客户端:" + tAddress().getHostAddress());
// 创建clientHandler线程
ClientHandlerThread clientRunnable = new ClientHandlerThread(s溺水作文 ocket, this);
Thread clientThread = new Thread(clientRunnable);
();
// 将成功获取到的客户端保存起来
if(socket != null){
synchronized(clientsMap){
(tAddress().getHostAddress(), clientRunnable);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
}
}
/**
* 关闭 ServerSocket
*/
public void finalize(){
// 关闭 ServerSocket
try {
();
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
tackTrace();
}
rverSocket = null;
}
}
class Message{
public String IP;
public String info;
public Message(String iP, String info) {
super();
IP = iP;
= info;
}
}
HandlerThread
客户端处理线程,当有⼀个客户端连⼊服务器时,启动⼀个线程接收客户端信息。
package ;
import putStream;
import tputStream;
import ption;
import ;
public class ClientHandlerThread implements Runnable {
// 客户端socket
public Socket clientSocket = null;
// socket 的输⼊,输出流
private DataInputStream in = null;
public DataOutputStream out = null;
// 服务器线程ServerThread
private ServerThread rverThread = null;
/**
* 构造函数
* @param socket
* @param rverThread
*/
public ClientHandlerThread(Socket socket, ServerThread rverThread){
Thread = rverThread;
Socket = socket;
// 获取对服务器操作的输⼊输出流
try {
in = new DataInputStream(utStream());
out = new DataOutputStream(putStream());
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
}
/**
* 监听对应的客户端是否有消息发送
*/
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
String iP = F();
String info = F();
Message message = new Message(iP, info);
// 打印接收信息
n("[" + tAddress().getHostAddress() + "] -> [" + + "]:" + );
// 将客户端发送的信息存储到 Message LIST中
synchronized (elt) {
(message);
}
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
break;
}
}
}
}
eHandlerThread
package ;
import ption;
import or;
public class MessageHandlerThread implements Runnable{
// 客户端线程
private ClientHandlerThread clientThread = null;
暖性食物 // 服务器线程
private ServerThread rverThread = null;
// 处理的消息
private Message message = null;
/**
* 构造函数
* @param rverThread
*/
public MessageHandlerThread(ServerThread rverThread){
Thread = rverThread;
}
@Override
public void ru熹妃传厨房攻略 n() {
// TODO Auto-generated method stub
while(true){
// 线程休眠100ms
try {
(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
tackTrace();
}
// 获取要处理的信息
synchronized (elt) {
// 判断是否有未发送的信息
if(y()){
continue;
}
message = (0);
}
// 处理信息
synchronized (sMap) {
if(("10.0.2.2")) = "127.0.0.1";
// 获取要发送的客户端
clientThread = ();
try {
// 获取所有⽤户
if(("{GETALL}")){
String info = "";
Iterator
while(t()) {
info += (()).tAddress().getHostAddress();
info += ";";
}
= info;
}
// 发送数据
TF();
TF();
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
// 从rver LIST中删除掉已经处理的消息
(message);
}
}
}
}
4-安卓客户端编程
S1 Socket通信模块编程
该设计按照单例模式设计,即全局不构造对象,类变量只有⼀个实例。
这样的设计提⾼了socket利⽤率,节省了代码量。
package ;
import putStream;
import tputStream;
import ption;
import ;
import nHostException;
public class ChatClient {
private static Socket clientSocket = null;
private static DataInputStream in = null;
private static DataOutputStream out = null;
private static String IP = "10.0.2.2";
private static int PORT = 8888;
public static Socket getSocket(){
if(clientSocket == null){
try {
clientSocket = new Socket(IP, PORT);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
tackTrace();
} catch (IOEsuv那个好 xception e) {
// TODO Auto-generated catch block
tackTrace();
}
}
return clientSocket;
}
public static DataInputStream getDataInputStream(){
if(in == null){
getSocket();
try {
in = new DataInputStream(utStream());
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
}
return in;
}
public static DataOutputStream getDataOutputStream(){
if(out == null){
getSocket();
try {
out = new DataOutputStream(putStream());
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
}
return out;
}
}
S2 安卓端界⾯简单设计
tivity
Spinner控件的设计,⽤于选择在线⽤户;
TextView控件为了显⽰聊天记录信息;
EditView控件为了获取⽤户输⼊的数据信息;
Button控件为了发送⽤户信息;
package tdemo;
import ption;
import ty;
import ;
import r;
import e;
import ;
import kListener;
import rView;
import SelectedListener;
import dapter;
import ;
import xt;
import r;
import ew;
import ient;
public class MainActivity extends Activity implements OnClickListener, Runnable {
private Spinner urList = null;
private Button ndBtn = null;
private EditText infoEdit = null;
private甘之如饴造句 String message = null;
private String[] mUrs = null;
private TextView infoArea = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
te(savedInstanceState);
tContentView(ty_main);
urList = (Spinner) ewById(st);
infoEdit = (EditText) findViewById(it);
ndBtn = (Button) findViewById(n);
infoArea = (TextView) findViewById(ea);
lickListener(this);
try {
//获得本机IP
InetAddress addr = alHost();
String ip = tAddress().toString();
aOutputStream().writeUTF(ip);
aOutputStream().writeUTF("{GETALL}");
String respon = aInputStream().readUTF();
mUrs = (";");
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
ArrayAdapter
_spinner_item, mUrs);
pDownViewResource(_spinner_dropdown_item);
pter(adapter);
new Thread(this).start();
}
@Override
public void onClick(View v) {
// TODO Auto-ge老爸生日祝福语 nerated method stub
switch(()){
ca n:
String ip = ectedItem().toString();
String info = t().toString();
try {
aOutputStream().writeUTF(ip);
aOutputStream().writ小说里的经典语录 eUTF(info);
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
break;
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
message = aInputStream().readUTF();
message += "n";
ssage(Message());
} catch (IOException e) {
// TODO Auto-generated catch block
tackTrace();
}
}
}
private Handler mHandler = new Handler(){
/**
* 获取⼀个消息,刷新对话框
*/
public void handleMessage(Message msg){
(message);
Message(msg);
}
};
}
ty_
xmlns:tools="/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > android:id="@+id/urList" android:layout_width="match_parent" android:layout_height="wrap_content" /> android:id="@+id/chatArea" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1.05"/> android:id="@+id/infoEdit" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" >
S3.增加联⽹权限
5-运⾏效果
先启动服务器,然后启动客户端,选择聊天对象,即可实现点对点通信。
PS.⼏点遗憾:
r控件没有获取到点击事件,导致⽆法更新在线⼈信息,但这个与socket通信⽆关,后期将会把更新版本补充上。
2.由于开启虚拟机测试,不能实现现场点对点通信(虚拟机IP相同导致的),真机测试,效果会更好。
3.之前想⽤传统的ObjectInputStream,然后将信息交换定义为⼀系列的Message类,但考虑到服务器不知⽤于java通信,如果这样写可
能会让跨语⾔通信失败。
本实例精华重在⼀个HashMap映射思想和,MessageHandlerThread消息处理线程的设计,⽤以实现的点点通信机制。
附上源码:
没有积分的请留⾔邮箱~
本文发布于:2023-04-21 22:23:26,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/fan/89/841735.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |