从零开始学android -- 简易的socket通信
先来介绍下socket,网上摘抄点资料,免得自己打字了
网络中进程之间如何通信?
本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:
- 1、消息传递(管道、FIFO、消息队列)
- 2、同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
- 3、共享内存(匿名的和具名的)
- 4、远程过程调用(Solaris门和Sun RPC)
但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说“一切皆socket”。
2、什么是Socket?
上面我们已经知道网络中的进程是通过socket来通信的,那什么是socket呢?socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
socket一词的起源:在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的,撰写者为Stephen Carr、Steve Crocker和Vint Cerf。根据美国计算机历史博物馆的记载,Croker写道:“命名空间的元素都可称为套接字接口。一个套接字接口构成一个连接的一端,而一个连接可完全由一对套接字接口规定。”计算机历史博物馆补充道:“这比BSD的套接字接口定义早了大约12年。”
TCP/IP协议基础
Ip协议是internet上使用的一个关键协议,它的全称是Intentnet Protocol ,即Internet协议,通常简称IP协议。通过IP协议,使Internet成为一个允许连接不同类型的计算机和不同操作系统的网络。
要使两台计算机彼此之间进行通信,必须使两台计算机使用一种“语言” ,IP协议只保证计算机能发送和接收分组数据。IP协议负责将消息从一个主机传送到另一个主机,消息在传送的过程中被分割成一个个小包。
尽管计算机通过安装IP软件,保证了计算机之间可以发送和接收数据,但IP协议还不能解决数据分组在传输过程中可能出现的问题。因此,若要解决可能出现的问题,连接上Internet的计算机还需要安装TCP协议来提供可靠并且无差错的通信服务。
TCP协议被称为一种端对端协议。这是因为它为两台计算机之间的连接起了重要作用:当一台计算机需要与另一台远程计算机连接时,TCP协议会让他们建立一个连接:用于发送和接收数据的虚拟链路。
TCP协议负责收集这些信息包。并将其按照适当的次序放好传送,在接收端收到后再将其正确的还原。TCP协议保证了数据包在传送中准确无误。TCP协议使用重发机制:当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体的确认消息,如果没有收到另一个通信实体的确认消息,则会再次重发刚才发送的消息。
通过这种重发机制。TCP协议向应用程序提供可靠的通信连接,使他能够自动适应网上的各种变化。即使在Internet暂时出现堵塞的情况下,TCP也能保证通信的可靠。
综上所述,虽然IP和TCP协议的功能不同,也可以分开单独使用,但它们是在同一时期作为一个协议来设计的,并且在功能上也是互补的。只有两者结合,才能保证Internet在复杂的环境下正常运行。凡是要连接Internet的计算机,都必须同时安装和使用这两个协议,因此在实际中常把这两个协议统称为TCP/IP协议。
使用ServerSocket创建TCP服务端
上图中我们可以看出Tcp通信的两个通信实体是没有区分服务端和客户端的,但是实在他们建立起连接后的状态。如果没有建立起连接的话,必须需要有一端释放出“主动”的姿态,等待连接,那么这一端就是服务端,连接的一端就是客户端。
先来看看效果:
服务端:pc上
客户端:真机和模拟器
目的:建立一个多客户端的简易聊天室。(下图你也能看到,模拟器连接上了,pc服务端会打印一个连接数1,真机连接上服务端了,pc端会打印一个连接数2)
PC服务端代码编写:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList; public class MyServer { public static ArrayList<Socket> socketList = new ArrayList<>(); public static void main(String[] args) { try {
//建立服务端
InetAddress inetAddress = InetAddress.getLocalHost();
//打印本地的ip
System.out.println("ip:"+inetAddress.getHostAddress());
ServerSocket serverSocket = new ServerSocket(30000);
while(true){
//循环接收socket
Socket socket = serverSocket.accept(); OutputStream os = socket.getOutputStream();
os.write(("欢迎连接Mdm服务端socket...\n").getBytes("utf-8"));
// os.close();
socketList.add(socket); //join in socketList
new Thread(new ServerThread(socket)).start(); //new thread Deal with this matter. System.out.println("当前连接数"+socketList.size());
} //that end java code written.
} catch (IOException e) {
e.printStackTrace();
}
} }
ServerThread.java
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 { BufferedReader br = null; Socket s; public ServerThread(Socket s){ try {
this.s = s;
br = new BufferedReader(new InputStreamReader(s.getInputStream(),"utf-8")); } catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} @Override
public void run() { String content = null;
//循环判断client发送过来的数据不为null
while((content = readFromClient()) != null){ //遍历每一列表中的每一个socket给他们发送消息类似聊天室的感觉每个人都收到了消息
for (Socket otherClient : MyServer.socketList) { try {
//输出流进行输出
OutputStream os = otherClient.getOutputStream();
os.write((content+"\n").getBytes("utf-8"));
// os.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
} }
} /**
* 获取从clientSocket中发过来的消息
* @return
*/
private String readFromClient(){ try {
return br.readLine();
} catch (IOException e) {
e.printStackTrace();
//if hava excption remove this socket in socketList.
MyServer.socketList.remove(s);
}
return null;
}
}
Android 客户端代码
activity_multi_thread_client.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="match_parent"
android:orientation="vertical"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <!--用来发送给服务端的数据-->
<EditText
android:id="@+id/input"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> <Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="send"
/>
</LinearLayout> <!--用来获取显示服务端发送过来的数据-->
<TextView
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top"
android:background="#ffff"
android:textSize="14dp"/> </LinearLayout>
MultiThreadClient.java
public class MultiThreadClient extends AppCompatActivity { private EditText input;
private TextView show; private Handler handler; private ClientThread clientThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_multi_thread_client); input = (EditText) findViewById(R.id.input);
show = (TextView) findViewById(R.id.show); handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//receive ServerSocket data.
if(msg.what == 0x123)
show.append("\n"+msg.obj.toString());
}
};
clientThread = new ClientThread(handler);
new Thread(clientThread).start(); Button send = (Button) findViewById(R.id.send);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { Message msg = Message.obtain();
msg.what = 0x345;
msg.obj = input.getText().toString();
clientThread.sendHandler.sendMessage(msg);
input.setText("");
}
}); }
}
ClientThread.java
public class ClientThread implements Runnable { //接收服务端发送的数据
private Handler handler; //send client data.
public Handler sendHandler; private BufferedReader br;
private OutputStream os; public ClientThread(Handler handler){
this.handler = handler;
}
@Override
public void run() {
try {
//connection server Socket
Socket socket = new Socket("192.168.1.110",30000);
br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
os = socket.getOutputStream(); //print server data in TextView
new Thread(){
@Override
public void run() {
try {
String content = null;
while ((content = br.readLine()) != null) {
Message msg = Message.obtain();
msg.what = 0x123;
msg.obj = content;
handler.sendMessage(msg);
}
}catch (IOException ex){
ex.printStackTrace();
}
}
}.start(); //send client data to server
Looper.prepare();
sendHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
try {
if(msg.what == 0x345) {
os.write((msg.obj.toString()+"\r\n").getBytes("utf-8")); //这地方后面一定得加上\n因为服务端那边readLine()读取的是以换行为结束标识。之前发不出去数据,代码调试了好久,头都大了。
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
} }
}
ok。
从零开始学android -- 简易的socket通信的更多相关文章
- Android简单实现Socket通信,client连接server后,server向client发送文字数据
案例实现的是简单的Socket通信,当client(Androidclient)连接到指定server以后,server向client发送一句话文字信息(你能够拓展其他的了) 先看一下服务端程序的实现 ...
- Android进程间通信之socket通信
用Java中的socket编程. 通过socket实现两个应用之间的通信,可以接收和发送数据,同时将接收到的数据显示在activity界面上. Server端: ServerLastly.java p ...
- 从零开始学android -- Service
废话不多说了,Service是四大组件之一,是一个后台处理长时间运行在主线程不需要依赖ui界面显示的应用组件,切记不能在service中做耗时操作,会阻塞主线程,要做也要在service中开个子线程做 ...
- 从零开始学android开发-通过WebService进行网络编程,使用工具类轻松实现
相信大家在平常的开发中,对网络的操作用到HTTP协议比较多,通过我们使用Get或者Post的方法调用一个数据接口,然后服务器给我们返回JSON格式的数据,我们解析JSON数据然后展现给用户,相信很多人 ...
- android中非堵塞socket通信
1.什么是同步与异步,堵塞与非堵塞 首先我们要明确搞明确:同步就等于堵塞?异步就等于非堵塞?这是不正确的,同步不等于阻 塞.而异步也不等于非堵塞. 1)那什么是同步编程? 什么是同步,就是在发出一个功 ...
- android wifi热点 socket通信
1.首先建立wifi热点服务器 wifi客户端连接 2.开启一个子线程循环监听某个端口,进行数据流输入输出 /* 服务器 接收数据 */ class Receiver extends Thread ...
- 从零开始学android开发-项目打包发布
右键项目 选择[android tools]-[export signed application package] 点击[next] 如果没有keystore可以选择[create new keys ...
- 从零开始学android开发-adt-bundle-eclipse下的修改android app名称
eclipse中,打开项目根目录中的AndoirManifest.xml文件,找到如下内容 <application android:allowBackup="true" a ...
- 从零开始学android开发-通过WebService获取今日天气情况
因为本身是在搞.NET方面的东东,现在在学习Android,所以想实现Android通过WebService接口来获取数据,网上很多例子还有有问题的.参考:Android 通过WebService进行 ...
随机推荐
- elasticsearch 分布式部署
修改配置文件 /config/elasticsearch.yml 我用两台机器,内网地址分别为230 和 231 处理启动报错一: [2017-01-12T15:55:55,433][INFO ][o ...
- 【SQL】在SQL Server中多表关联查询问题
好久没有写SQL语句的多表连接查询,总在用框架进行持久化操作.今天写了一个多表关联查询,想根据两个字段唯一确定一条数据 失败的案例如下: SELECT cyb.id,ad.name FROM [Gen ...
- 2017.7.1 mysql安装与启动(已验证可以使用)
下载地址:http://learning.happymmall.com/ 之前一直用解压版安装,启动mysql服务的时候总是失败,这次用mysql installer安装一遍,终于成功启动. 1.下载 ...
- Angular 学习笔记——ng-animate
<!DOCTYPE HTML> <html ng-app="myApp"> <head> <meta http-equiv="C ...
- mysql 修改字符集为utf8mb4
一般情况下,我们会设置MySQL默认的字符编码为utf8,但是近些年来,emoji表情的火爆使用,给数据库带来了意外的错误,就是emoji的字符集已经超出了utf8的编码范畴
- 倍福TwinCAT(贝福Beckhoff)基础教程 松下驱动器试运行提示过速度保护怎么办
在试运行的时候,取消勾选自动设定,然后可以自己设置过速度等级设置和过载等级设置 更多教学视频和资料下载,欢迎关注以下信息: 我的优酷空间: http://i.youku.com/acetaoh ...
- iOS 引入外部字体 otf/ttf/ttc
1.首先下载到字体的otf文件(Mac电脑下搜索字体册) 2.将字体文件拖到项目工程下 3.plist设置 Fonts provided by application 属性 4.代码中使用[UIFon ...
- defer,panic,recover
Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个 ...
- MySQL 系列教程(二) 你不知道的数据库操作
本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网远程连接法 查看\创建\使用\删除\清空\修改 数据库表(是否可空,默认值,主键,自增,外键) 表内容的增删改查 where条件. ...
- mkdir的参数-p的作用
mkdir -p /nfs 也就是加上-p参数,之前只知道是递归创建目录,于是就发问了,得到的答案是: -p, --parents no error if existing, ...