概述
本文讲述了:
1、如何在Android上搭建Mina服务端(使用Mina 2.0.15、编程环境Eclipse);
2、如何在iOS上建立Socket客户端(使用CocoaAsyncSocket第三方通讯框架、Swift3.0);
3、Android iOS间的TCPSocket通讯测试。
一、在Android上搭建Mina服务端
1、下载Mina最新版
直接进官网:http://mina.apache.org/ 进入后左边栏上方有一个 Latest Downloads — Mina x.x.xx,点击进入后如下图。
点击标注的这项,进入下一个界面。
用它建议的这个链接下载Mina最新版,下载后是一个zip包。解压它,如下图。(我用的是Mina 2.0.15,都一样)
好,到这里Mina的准备工作算是完成了。
2、下面开始搭建Mina服务端,打开Eclipse,建立Android工程(这里将工程命名为MinaServer)。然后就是使用Mina了,就是在自己的工程中导入Mina提供的第三方jar包。
在刚才解压得到的Mina文件夹中找到 dist - mina-core-x.x.xx 和 lib - slf4j-api-x.x.xx这两个Jar包,然后将他们拖到我们工程的libs文件夹中,选中它俩 右击 - Build Path - Add to Build Path,下面图片是导入后的图片,导入后会多出一个Referenced Libraries 里面有我们刚刚添加的那两个第三方包。到这里我们就将Mina导入进了我们的项目。
(其实导入包的方法不只这一种,还有别的方法,我也尝试了,因为别的方法看上去比这一种显得正规,但是在程序运行中会报错:Could not find class ‘org.apache.mina.transport.socket.nio.NioSocketAcceptor’, referenced from method alex.example.minaserver.MainActivity.onCreate,这个问题的解决方案就是用这种看着不专业的jar包导入方法。网上有不少人遇到此问题,可见此坑之深…)
3、写Mina服务端代码(这里不做解释,因为我也没彻底玩透Mina框架,只是会简单使用,也和大家一样是小白)
打开 MinaActivity.java
package alex.example.minaserver;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends Activity {
// Mina相关声明-----------------------
private IoAcceptor acceptor;
private static int PORT = 4000; // 端口号,要求客户端与服务器端一致
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Log.d("Mina", "开始启动 MinaServer...");
// 创建一个非阻塞的server端的Socket
acceptor = new NioSocketAcceptor();
// 设置过滤器(使用mina提供的文本换行符编解码器)
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue())));
// 设置读取数据的换从区大小
// acceptor.getSessionConfig().setReadBufferSize(2048);
// 读写通道10秒内无操作进入空闲状态
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 为接收器设置管理服务
acceptor.setHandler(new DemoServerHandler());
((NioSocketAcceptor) acceptor).setReuseAddress(true); // 端口重用,如果有客户端在wait状态,服务器重启但是端口释放不掉
// 绑定端口
acceptor.bind(new InetSocketAddress(PORT));
Log.d("Mina", "服务器启动成功,端口号为:" + PORT);
Toast.makeText(MainActivity.this, "服务器启动成功", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.d("Mina", "服务器启动异常..." + e);
Toast.makeText(MainActivity.this, "服务器启动失败", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
// Mina --- IoHandlerAdapter处理Mina通信中的各种事件 --------------------
public class DemoServerHandler extends IoHandlerAdapter {
// 从端口接受消息,会响应此方法来对消息进行处理
public void messageReceived(IoSession session, Object message) throws Exception {
super.messageReceived(session, message);
String recvMsg = message.toString();
Log.d("Mina", "*** Start *** 服务器收到消息:" + recvMsg);
session.write("Received");
}
// 向客服端发送消息后会调用此方法
public void messageSent(IoSession session, Object message) throws Exception {
super.messageSent(session, message);
// session.close(true); // 加上这句话实现短连接的效果,向客户端成功发送数据后断开连接
Log.d("Mina", "*** End *** 向客户端发送消息:" + message.toString());
}
// 关闭与客户端的连接时会调用此方法
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
Log.d("Mina", "服务器与客户端断开连接...");
}
// 服务器与客户端创建连接
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
Log.d("Mina", "服务器与客户端创建连接...");
}
// 服务器与客户端连接打开
public void sessionOpened(IoSession session) throws Exception {
Log.d("Mina", "服务器与客户端连接打开...");
super.sessionOpened(session);
}
// 服务器进入空闲状态IDLE会调用此方法
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
super.sessionIdle(session, status);
Log.d("Mina", "服务器进入空闲状态...");
}
// 服务器捕捉到异常会调用此方法
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
super.exceptionCaught(session, cause);
Log.d("Mina", "服务器出现异常:" + cause.toString());
}
}
}
这还不算完,因为这个App需要联网,所以别忘了添加权限。
打开 AndroidManifest.xml(权限有的用不到,带着没妨碍)
<!-- **************** 网 络 ***************** -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
4、Mina服务端到此就完成了,下面运行下试试,我是用的真机调试的,所以不方便图片展示,下图只展示Log中的内容。
二、在iOS上建立Socket客户端(Swift3.0)
1、下载和使用CocoaAsyncSocket。
https://github.com/robbiehanson/CocoaAsyncSocket
下载完成解压得到如下图文件夹。
下面开始将它导入到我们的App项目中,将上图圈中的两个文件直接拖进xCode左边栏的工程中,如下图。
将这两个文件拖进xCode后它会提示你是否建立一个Bridge-Header,就点击Create。
然后点击这个Bridge-Header文件并输入。
#import "GCDAsyncSocket.h"
这时候按下Command+B重新编译一下。这样CocoaAsyncSocket就导入完毕了。
2、客户端程序
界面展示
编写代码,进入ViewController.Swift
//
// ViewController.swift
// AsyncSocket_Exp
//
// Created by 大老虎 on 2016/11/29.
// Copyright © 2016年 Tiger. All rights reserved.
//
import UIKit
class ViewController: UIViewController, GCDAsyncSocketDelegate {
@IBOutlet weak var serveripInput: UITextField!
@IBOutlet weak var msgInput: UITextField!
@IBOutlet weak var conBtn: UIButton!
@IBOutlet weak var sendBtn: UIButton!
@IBOutlet weak var msgView: UITextView!
let serverPort: UInt16 = 4000 // 和上面的服务端一致
var clientSocket:GCDAsyncSocket!
override func viewDidLoad() {
super.viewDidLoad()
sendBtn.isEnabled = false // Socket未连接成功时发送按钮不能用
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 连接服务器按钮事件
@IBAction func conBtnClick(_ sender: AnyObject) {
if serveripInput.text?.isEmpty == false { // 如果IP地址不为空则开始连接Socket
clientSocket = GCDAsyncSocket()
clientSocket.delegate = self
clientSocket.delegateQueue = DispatchQueue.global()
do {
try clientSocket.connect(toHost: serveripInput.text!, onPort: serverPort)
} catch {
print("error")
conBtn.backgroundColor = UIColor.red
}
} else {
msgView.insertText("IP地址不能为空!n")
}
}
func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) -> Void {
print("连接成功")
sendBtn.isEnabled = true // 连接成功后发送按钮设为可用
clientSocket.readData(withTimeout: -1, tag: 0)
}
func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) -> Void {
print("与服务器断开连接")
}
func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) -> Void {
// 1、获取客户端发来的数据,把 NSData 转 NSString
let readClientDataString: NSString? = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue)
print("---Data Recv---")
print(readClientDataString)
// 2、主界面UI显示数据
DispatchQueue.main.async {
let showStr: NSMutableString = NSMutableString()
showStr.append(self.msgView.text)
showStr.append(readClientDataString! as String)
showStr.append("n")
self.msgView.text = showStr as String
}
// 3、处理请求,返回数据给客户端OK
// let serviceStr: NSMutableString = NSMutableString()
// serviceStr.append("OKrn")
// clientSocket.write(serviceStr.data(using: String.Encoding.utf8.rawValue)!, withTimeout: -1, tag: 0)
// 4、每次读完数据后,都要调用一次监听数据的方法
clientSocket.readData(withTimeout: -1, tag: 0)
}
// 发送消息按钮事件
@IBAction func sendBtnClick(_ sender: AnyObject) {
if msgInput.text?.isEmpty == false { // 如果消息不为空则发送
let serviceStr: NSMutableString = NSMutableString()
serviceStr.append(self.msgInput.text!)
serviceStr.append("rn")
clientSocket.write(serviceStr.data(using: String.Encoding.utf8.rawValue)!, withTimeout: -1, tag: 0)
}
}
}
这段代码和上一篇博文99%是一样的,只是在发送的地方不同,每次发送的结尾都要加上rn,只有这样才能保证Android Mina服务端能收到我们发送的信息,否则,客户端只能与服务端建立连接,而客户端发送过去的信息服务端无法正常处理。
三、跨平台通信测试
1、打开服务端和客户端程序;
2、看服务端的Log中是否建立服务端成功;
3、在客户端输入服务端的ip地址,这个ip地址指的是局域网中的地址,外网ip地址我没测试过,点击连接。双方Log是否连接成功。
4、客户端发送信息给服务端,服务端收到信息反馈给客户端,客户端接受到反馈信息,完毕。
5、关闭客户端,服务端Log显示断开连接。
6、测试完毕。
下面是我测试的图片,我的服务端使用的三星平板电脑,客户端使用的模拟器iphone6s 10.0,客户端也在真机上跑过,没问题,真机使用的iphoneSE 10.1.1。
大功告成啦!大家可以自己试一试,这里不提供源码下载了,所有核心代码都在文中了。大家加油!
最后
以上就是无辜哈密瓜为你收集整理的Socket跨平台通信——服务端Android、客户端iOS的全部内容,希望文章能够帮你解决Socket跨平台通信——服务端Android、客户端iOS所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复