首页 文章 精选 留言 我的

精选列表

搜索[通信],共10001篇文章
优秀的个人博客,低调大师

Android NFC(近程通信)使用

添加权限 <uses-permission android:name="android.permission.NFC" /> 1. 读写文本 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入要写入的文本"/> <TextView android:hint="卡中内容" android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> MainActivity.java public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; /**写入内容的文本框*/ private EditText mEditText; /**显示NFC卡中的内容*/ private TextView mTextView; /**NFC相关*/ /**NFC适配器*/ private NfcAdapter mNfcAdapter; /**延时意图*/ private PendingIntent mPendingIntent; /**检测的卡类型*/ private static String[][] sTechArr = null; /**意图过滤器*/ private static IntentFilter[] sFilters = null; static { try { sTechArr = new String[][]{ {IsoDep.class.getName()}, {NfcV.class.getName()}, {NfcF.class.getName()}, {MifareUltralight.class.getName()}, {NfcA.class.getName()} }; // 如果这里不设置过滤器,就必须要在AndroidManifest.xml中为MainActivity设置过滤器 // 这里的ACTION在NfcAdapter中有四个选中,个人认为是在设置响应优先级 /** * <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> */ sFilters = new IntentFilter[]{ new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED, "*/*") }; } catch (Exception e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initNfc(); // 判断当前手机是否支持NFC if (null == mNfcAdapter) { // 如果为null,则为不支持。 Toast.makeText(this, "当前设备不支持NFC功能!", Toast.LENGTH_SHORT).show(); return; } } /** * 初始化NFC */ private void initNfc() { // 1. 初始化Nfc适配器 mNfcAdapter = NfcAdapter.getDefaultAdapter(this); // 2. 初始化延时意图 mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); } @Override protected void onResume() { super.onResume(); // 3. 允许后台唤醒--此处是指应用处于不可见的状态时,将卡片贴近手机时,唤醒当前App。 // 如果sFilters为null,则为不过滤任何意图;如果sTechArr为null时,则为接收所有类型的卡片。 mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, sFilters, sTechArr); } @Override protected void onPause() { super.onPause(); // 4. 禁止后台唤醒 mNfcAdapter.disableForegroundDispatch(this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 5. 重写OnIntent方法, 读取到的数据存储在intent中 // 获取到意图中的Tag数据 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // TAG: Tech [android.nfc.tech.NfcV, android.nfc.tech.Ndef] Log.e(TAG, "onNewIntent: " + tag); // 此处判断输入框mEditText的内容是否为空,如果为空,则为读取数据;如果不为空,则为写入数据 if (TextUtils.isEmpty(mEditText.getText().toString())) { // 数据为空,读取数据 readData(tag); } else { // 数据不为空,写入数据 writeData(tag); } } /** * 读取数据 * @param tag Tag */ private void readData(Tag tag) { // 从Tag中获取Ndef信息 Ndef ndef = Ndef.get(tag); try { // 连接 ndef.connect(); // readData: type: android.ndef.unknown, size: 250, message: NdefMessage [NdefRecord tnf=1 type=54 payload=027A68E4BDA0E5A5BD] Log.e(TAG, "readData: type: " + ndef.getType() + ", size: " + ndef.getMaxSize() + ", message: " + ndef.getNdefMessage().toString()); // 获取NdefMessage消息 NdefMessage ndefMessage = ndef.getNdefMessage(); // 获取NdefRecord记录 //ndefMessage.getRecords(); // 遍历数组 StringBuilder stringBuilder = new StringBuilder(); // 文本 String text; for (NdefRecord ndefRecord : ndefMessage.getRecords()) { text = parseNdefRecord(ndefRecord); if (!TextUtils.isEmpty(text)) { stringBuilder.append(text); } } // 设置文本 mTextView.setText(stringBuilder.toString()); } catch (IOException | FormatException e) { e.printStackTrace(); } } /** * 解析NdefRecord数据 * @param ndefRecord NdefRecord记录 */ private String parseNdefRecord(NdefRecord ndefRecord) { // 判断是否为文本格式数据 if (NdefRecord.TNF_WELL_KNOWN != ndefRecord.getTnf()) { return ""; } if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) { return ""; } try { // 获得字节流 byte[] payload = ndefRecord.getPayload(); // 获得编码格式 String textEncoding = ((payload[0] & 0x80) == 0) ? "utf-8" : "utf-16"; // 获得语言编码长度 int languageCodeLength = payload[0] & 0x3f; // 语言编码 String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII"); // 获取文本 return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength -1, textEncoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } /** * 写数据 * @param tag Tag */ private void writeData(Tag tag) { // 创建一个NdefMessage消息 NdefMessage ndefMessage = new NdefMessage(createTextRecord(mEditText.getText().toString())); // 写入Tag if (writeTag(ndefMessage, tag)) { mEditText.setText(""); Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show(); } } /** * 将NdefMessage消息写入Tag * @param ndefMessage Ndef消息 * @param tag Tag */ private boolean writeTag(NdefMessage ndefMessage, Tag tag) { try { // 获取Ndef Ndef ndef = Ndef.get(tag); // 连接 ndef.connect(); // 写入数据 ndef.writeNdefMessage(ndefMessage); return true; } catch (IOException | FormatException e) { e.printStackTrace(); } return false; } /** * 创建文本信息 * @param text 要写入的文本信息 */ private NdefRecord createTextRecord(String text) { // 设置语言 byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII")); // 设置编码 Charset utfEncoding = Charset.forName("UTF-8"); // 要写入的二进制数据 byte[] textBytes = text.getBytes(utfEncoding); int utfBit = 0; // 将语言长度转化对应的字符 char status = (char)(utfBit + langBytes.length); // 创建一个大小为 1(即语言长度转化对应的字符) + 语言字节长度 + 文本字节长度的字节数组 byte[] data = new byte[1 + langBytes.length + textBytes.length]; // 写入第一位数据 data[0] = (byte) status; // 写入语言字节 System.arraycopy(langBytes, 0, data, 1, langBytes.length); // 写入文本数据 System.arraycopy(textBytes, 0, data, langBytes.length + 1, textBytes.length); // 创建一个NdefRecord记录 return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); } /** * 初始化布局 */ private void initView() { mEditText = (EditText) this.findViewById(R.id.editText); mTextView = (TextView) this.findViewById(R.id.textView); } } 2. NFC读写Uri 对NFC的配置信息相同,此处只是更改读取与写入的操作。 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 5. 重写OnIntent方法, 读取到的数据存储在intent中 // 获取到意图中的Tag数据 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // TAG: Tech [android.nfc.tech.NfcV, android.nfc.tech.Ndef] Log.e(TAG, "onNewIntent: " + tag); // 此处判断输入框mEditText的内容是否为空,如果为空,则为读取数据;如果不为空,则为写入数据 if (TextUtils.isEmpty(mEditText.getText().toString())) { // 数据为空,读取数据 readData(tag); } else { // 数据不为空,写入数据 writeData(tag); } } /** * 写入Uri * http://www.baidu.com/ * @param tag */ private void writeData(Tag tag) { // 创建一个Uri Uri uri = Uri.parse(mEditText.getText().toString()); // 创建一个NdefMessage格式数据 NdefMessage ndefMessage = new NdefMessage(NdefRecord.createUri(uri)); if (writeTag(ndefMessage, tag)) { Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); mEditText.setText(""); } } /** * 写入数据 * @param ndefMessage Ndef格式数据 * @param tag Tag * @return true,写入成功;false,写入失败 */ private boolean writeTag(NdefMessage ndefMessage, Tag tag) { // 计算写入数据的长度 int size = ndefMessage.toByteArray().length; try { // 获取Ndef Ndef ndef = Ndef.get(tag); if (null != ndef) { // 连接NFC卡片 ndef.connect(); // 判断NFC芯片是否可写 if (!ndef.isWritable()) { Toast.makeText(this, "卡片不可写", Toast.LENGTH_SHORT).show(); return false; } // 判断要写入的数据是否大于NFC芯片最大字节数 if (ndef.getMaxSize() < size) { Toast.makeText(this, "写入数据过大", Toast.LENGTH_SHORT).show(); return false; } ndef.writeNdefMessage(ndefMessage); return true; } else { // 获取一个格式化工具 NdefFormatable formatable = NdefFormatable.get(tag); // 判断是否为空 if (null != formatable){ // 连接 formatable.connect(); // 格式化并写入数据 formatable.format(ndefMessage); Toast.makeText(this, "格式化成功,并成功写入数据", Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this, "无法格式化", Toast.LENGTH_SHORT).show(); } } } catch (IOException | FormatException e) { e.printStackTrace(); } return false; } /** * 读取数据 * @param tag Tag */ private void readData(Tag tag) { try { // 获取Ndef Ndef ndef = Ndef.get(tag); // 连接 ndef.connect(); Log.e(TAG, "readData: type: " + ndef.getType() + ", size: " + ndef.getMaxSize() + ", message: " + ndef.getNdefMessage().toString()); // 获取Ndef格式数据 NdefMessage ndefMessage = ndef.getNdefMessage(); // 获取信息中的记录 NdefRecord[] records = ndefMessage.getRecords(); // 判断是否有数据 if (null != records && records.length > 0) { StringBuilder stringBuilder = new StringBuilder(); // 迭代 for (NdefRecord ndefRecord : records) { Uri uri = ndefRecord.toUri(); if (null != uri) { stringBuilder.append(uri.toString()); } } String string = stringBuilder.toString(); mTextView.setText(string); if (string.startsWith("http://")) { // 跳转网页 startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(stringBuilder.toString()))); } } // 断开连接 ndef.close(); } catch (IOException | FormatException e) { e.printStackTrace(); } } 3. 读写非Ndef格式数据 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 5. 重写OnIntent方法, 读取到的数据存储在intent中 // 获取到意图中的Tag数据 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // 可打印出当前NFC芯片支持的NFC类型 // onNewIntent: TAG: Tech [android.nfc.tech.NfcA, android.nfc.tech.MifareUltralight, android.nfc.tech.NdefFormatable] Log.e(TAG, "onNewIntent: " + tag); // 此处判断输入框mEditText的内容是否为空,如果为空,则为读取数据;如果不为空,则为写入数据 if (TextUtils.isEmpty(mEditText.getText().toString())) { // 数据为空,读取数据 readData(tag); } else { // 数据不为空,写入数据 writeData(tag); } } /** * 写数据 * @param tag Tag */ private void writeData(Tag tag) { // 获取到MifareUltralight MifareUltralight ultralight = MifareUltralight.get(tag); try { // 连接 ultralight.connect(); // Write 1 page (4 bytes). // 往每一页写数据,最多写四个字节 ultralight.writePage(4,"中国".getBytes(Charset.forName("gb2312"))); ultralight.writePage(5,"美国".getBytes(Charset.forName("gb2312"))); ultralight.writePage(6,"英国".getBytes(Charset.forName("gb2312"))); ultralight.writePage(7,"法国".getBytes(Charset.forName("gb2312"))); Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); mEditText.setText(""); // 关闭连接 ultralight.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 读数据 * @param tag Tag */ private void readData(Tag tag) { // 获取连接 MifareUltralight ultralight = MifareUltralight.get(tag); try { // 连接 ultralight.connect(); byte[] bytes = ultralight.readPages(4); mTextView.setText(new String(bytes, Charset.forName("gb2312"))); // 断开连接 ultralight.close(); } catch (IOException e) { e.printStackTrace(); } } 4. AndroidBeam打开其他手机应用 /** * 测试方法, 将两部手机靠近,AndroidBeam接触时,两部手机界面同时缩小居中,轻触处理数据的手机一方,即可完成发送, * 放松数据期间手机不能离开,离开之后即会断开连接,终止发送。 */ public class MainActivity extends AppCompatActivity implements NfcAdapter.CreateNdefMessageCallback, NfcAdapter.OnNdefPushCompleteCallback{ private static final String TAG = "MainActivity"; private NfcAdapter mNfcAdapter; private PendingIntent mPendingIntent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0); // 设置发送消息的回调 mNfcAdapter.setNdefPushMessageCallback(this, this); // 设置发送完成回调 mNfcAdapter.setOnNdefPushCompleteCallback(this, this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Toast.makeText(this, "NFC靠近", Toast.LENGTH_SHORT).show(); } /** * 当有NFC靠近时调用该方法 */ @Override public NdefMessage createNdefMessage(NfcEvent event) { // 将"com.mazaiting.nfc2"更换为另一部手机中已存在的应用包名 return new NdefMessage(NdefRecord.createApplicationRecord("com.mazaiting.nfc2")); } /** * 数据发送完成时调用方法 */ @Override public void onNdefPushComplete(NfcEvent event) { Toast.makeText(this, "发送完成", Toast.LENGTH_SHORT).show(); } @Override protected void onResume() { super.onResume(); mNfcAdapter.enableForegroundDispatch(this,mPendingIntent, null,null); } @Override protected void onPause() { super.onPause(); mNfcAdapter.disableForegroundDispatch(this); } } AndroidBeam接触时如下图: 图1.png 5. AndroidBeam传送大文件 1). 添加权限,一定不能忘记 <uses-permission android:name="android.permission.NFC"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 2). 在assets文件夹放一张图片或者文件,或者直接指定手机中的文件地址。 public class MainActivity extends AppCompatActivity implements NfcAdapter.CreateBeamUrisCallback, NfcAdapter.OnNdefPushCompleteCallback { private static final String TAG = "MainActivity"; private NfcAdapter mNfcAdapter; private PendingIntent mPendingIntent; private final String targetFilename = "/sdcard/image.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); mPendingIntent = PendingIntent.getActivity(this,0, new Intent(this,getClass()),0); try{ InputStream is = getResources().getAssets().open("image.jpg"); FileOutputStream fos = new FileOutputStream(targetFilename); byte[] buffer = new byte[1024]; int len = 0; while((len = is.read(buffer))!=-1){ fos.write(buffer,0,len); } fos.close(); is.close(); }catch (Exception e){ e.printStackTrace(); } // 设置回调 mNfcAdapter.setBeamPushUrisCallback(this, this); mNfcAdapter.setOnNdefPushCompleteCallback(this, this); } @Override public Uri[] createBeamUris(NfcEvent event) { Uri[] uris = new Uri[1]; Uri uri = Uri.parse("file://" + targetFilename); uris[0]=uri; return uris; } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Toast.makeText(this, "接触", Toast.LENGTH_SHORT).show(); } @Override protected void onResume() { super.onResume(); mNfcAdapter.enableForegroundDispatch(this,mPendingIntent, null,null); } @Override protected void onPause() { super.onPause(); mNfcAdapter.disableForegroundDispatch(this); } @Override public void onNdefPushComplete(NfcEvent event) { // 另一部手机接收的文件位置--/storage/emulated/0/beam/传输的文件名 Log.e(TAG, "onNdefPushComplete: "); } }

优秀的个人博客,低调大师

android 37 线程通信Looper

安卓程序的主线程也叫UI线程。 工作线程和主线程的差别:安卓主线程已经调用了Looper.prepare()方法了,已经有一个MessageQueue对象了,所以才可以在工作线程用Handler发消息到主线程:因为主线程有消息队列,发的消息都存在队列里面,并且主线程已经有Looper进行取消息了。 自己创建的工作线程是没有MessageQueue和Looper,所以不能向工作线程发消息,因为没有存消息的地方和取消息的东西。但是他可以有MessageQueue和Looper。 MessageQueue是消息队列,Looper轮训从消息队列中取消息,Handler用于发送和处理消息。 mainActivity: package com.sxt.day06_02; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { ProgressBar mProgressBar; TextView mtvProgress; static final int DOWNLOAD_START=0; static final int DOWNLOADING=1; static final int DOWNLOAD_FINISH=2; Handler mMainHanlder,mWokrThreadHanler;//主线程和工作线程的Handler,分别处理消息。 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initMainHandler(); setListener();//下载按钮的监听器 createWorkThread(); } private void createWorkThread() { new Thread(){//工作线程 public void run() {//Looper和mWokrThreadHanler都是在工作线程创建 Looper.prepare();//创建Looper对象和工作线程中的MessageQueue mWokrThreadHanler=new Handler(){ public void handleMessage(Message msg) { if(msg.what==DOWNLOAD_START){ Log.i("main","work thread start downlad"); for(int i=1;i<=100;i++){ SystemClock.sleep(20); Message msg2 = Message.obtain(); msg2.what=DOWNLOADING; msg2.arg1=i; mMainHanlder.sendMessage(msg2);//发送到主线程的消息队列,然后主线程的Looper从主线程消息队列取出来,调用mMainHanlder处理 mProgressBar.setProgress(i); } //循环结束后发送完成消息 Message msg2 = Message.obtain(); msg2.what=DOWNLOAD_FINISH; mMainHanlder.sendMessage(msg2);//发送到主线程 } }; }; Looper.loop();//轮询MessageQueue,取到消息后交给mWokrThreadHanler的handleMessage()方法进行处理(上面的方法), }; }.start(); } private void setListener() { findViewById(R.id.btnStartDownload).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //工作线程Handler向自己工作线程发送消息,发送至工作线程的消息队列MessageQueue中,空消息通知工作线程开始下载 mWokrThreadHanler.sendEmptyMessage(DOWNLOAD_START); } }); } private void initMainHandler() { mMainHanlder=new Handler(){//在主线程new,所以为主线程服务 @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOADING: mtvProgress.setText(msg.arg1+"%"); break; case DOWNLOAD_FINISH: Toast.makeText(MainActivity.this, "下载完成", 2000).show(); break; } } }; } private void initView() { mProgressBar=(ProgressBar) findViewById(R.id.pb); mtvProgress=(TextView) findViewById(R.id.tvProgress); } } 页面: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/btnStartDownload" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="开始下载" /> <ProgressBar android:id="@+id/pb" android:layout_width="match_parent" android:layout_height="wrap_content" style="@android:style/Widget.ProgressBar.Horizontal" android:max="100"/> <TextView android:id="@+id/tvProgress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:text="0%"/> </LinearLayout> 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4889490.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

IOS上的socket通信

客户端: 导入头文件: #import <sys/socket.h> #import <netinet/in.h> #import <arpa/inet.h> #import <unistd.h> 1. 创建连接 CFSocketContext sockContext = {0, // 结构体的版本,必须为0 self,// 一个任意指针的数据,可以用在创建时CFSocket对象相关联。这个指针被传递给所有的上下文中定义的回调。 NULL, // 一个定义在上面指针中的retain的回调, 可以为NULL NULL, NULL}; CFSocketRef _socket = (kCFAllocatorDefault, // 为新对象分配内存,可以为nil PF_INET, // 协议族,如果为0或者负数,则默认为PF_INET SOCK_STREAM, // 套接字类型,如果协议族为PF_INET,则它会默认为SOCK_STREAM IPPROTO_TCP, // 套接字协议,如果协议族是PF_INET且协议是0或者负数,它会默认为IPPROTO_TCP kCFSocketConnectCallBack, // 触发回调函数的socket消息类型,具体见Callback Types TCPServerConnectCallBack, // 上面情况下触发的回调函数 &sockContext // 一个持有CFSocket结构信息的对象,可以为nil ); if (_socket != nil) { struct sockaddr_in addr4; // IPV4 memset(&addr4, 0, sizeof(addr4)); addr4.sin_len = sizeof(addr4); addr4.sin_family = AF_INET; addr4.sin_port = htons(8888); addr4.sin_addr.s_addr = inet_addr([strAddress UTF8String]);// 把字符串的地址转换为机器可识别的网络地址 // 把sockaddr_in结构体中的地址转换为Data CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4)); CFSocketConnectToAddress(_socket, // 连接的socket address, // CFDataRef类型的包含上面socket的远程地址的对象 -1// 连接超时时间,如果为负,则不尝试连接,而是把连接放在后台进行,如果_socket消息类型为kCFSocketConnectCallBack,将会在连接成功或失败的时候在后台触发回调函数 ); CFRunLoopRef cRunRef = CFRunLoopGetCurrent();// 获取当前线程的循环 // 创建一个循环,但并没有真正加如到循环中,需要调用CFRunLoopAddSource CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0); CFRunLoopAddSource(cRunRef, // 运行循环 sourceRef,// 增加的运行循环源, 它会被retain一次 kCFRunLoopCommonModes// 增加的运行循环源的模式 ); CFRelease(courceRef); } 2. 设置回调函数 // socket回调函数的格式: static void TCPServerConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { if (data != NULL) { // 当socket为kCFSocketConnectCallBack时,失败时回调失败会返回一个错误代码指针,其他情况返回NULL NSLog(@"连接失败"); return; } TCPClient *client = (TCPClient *)info; // 读取接收的数据 [info performSlectorInBackground:@selector(readStream) withObject:nil]; } 3. 接收发送数据 // 读取接收的数据 - (void)readStream { char buffer[1024]; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; while (recv(CFSocketGetNative(_socket), //与本机关联的Socket 如果已经失效返回-1:INVALID_SOCKET buffer, sizeof(buffer), 0)) { NSLog(@"%@", [NSString stringWithUTF8String:buffer]); } } // 发送数据 - (void)sendMessage { NSString *stringTosend = @"你好"; char *data = [stringTosend UTF8String]; send(SFSocketGetNative(_socket), data, strlen(data) + 1, 0); } 服务器端: CFSockteRef _socket; CFWriteStreamRef outputStream = NULL; int setupSocket() { _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, TCPServerAcceptCallBack, NULL); if (NULL == _socket) { NSLog(@"Cannot create socket!"); return 0; } int optval = 1; setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_REUSEADDR, // 允许重用本地地址和端口 (void *)&optval, sizeof(optval)); struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_len = sizeof(addr4); addr4.sin_family = AF_INET; addr4.sin_port = htons(port); addr4.sin_addr.s_addr = htonl(INADDR_ANY); CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4)); if (kCFSocketSuccess != CFSocketSetAddress(_socket, address)) { NSLog(@"Bind to address failed!"); if (_socket) CFRelease(_socket); _socket = NULL; return 0; } CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent(); CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0); CFRunLoopAddSource(cfRunLoop, source, kCFRunLoopCommonModes); CFRelease(source); return 1; } // socket回调函数,同客户端 void TCPServerAcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { if (kCFSocketAcceptCallBack == type) { // 本地套接字句柄 CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data; uint8_t name[SOCK_MAXADDRLEN]; socklen_t nameLen = sizeof(name); if (0 != getpeername(nativeSocketHandle, (struct sockaddr *)name, &nameLen)) { NSLog(@"error"); exit(1); } NSLog(@"%@ connected.", inet_ntoa( ((struct sockaddr_in *)name)->sin_addr )): CFReadStreamRef iStream; CFWriteStreamRef oStream; // 创建一个可读写的socket连接 CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &iStream, &oStream); if (iStream && oStream) { CFStreamClientContext streamContext = {0, NULL, NULL, NULL}; if (!CFReadStreamSetClient(iStream, kCFStreamEventHasBytesAvaiable, readStream, // 回调函数,当有可读的数据时调用 &streamContext)){ exit(1); } if (!CFReadStreamSetClient(iStream, kCFStreamEventCanAcceptBytes, writeStream, &streamContext)){ exit(1); } CFReadStreamScheduleWithRunLoop(iStream, CFRunLoopGetCurrent(), kCFRunLoopCommomModes); CFWriteStreamScheduleWithRunLoop(wStream, CFRunLoopGetCurrent(), kCFRunLoopCommomModes); CFReadStreamOpen(iStream); CFWriteStreamOpen(wStream); } else { close(nativeSocketHandle); } } } // 读取数据 void readStream(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) { UInt8 buff[255]; CFReadStreamRead(stream, buff, 255); printf("received: %s", buff); } void writeStream (CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) { outputStream = stream; } main { char *str = "nihao"; if (outputStream != NULL) { CFWriteStreamWrite(outputStream, str, strlen(line) + 1); } else { NSLog(@"Cannot send data!"); } } // 开辟一个线程线程函数中 void runLoopInThread() { int res = setupSocket(); if (!res) { exit(1); } CFRunLoopRun();// 运行当前线程的CFRunLoop对象 } 本文转自 卓行天下 51CTO博客,原文链接:http://blog.51cto.com/9951038/1787766,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册