一、基于TCP协议的网络通信
TCP协议基础
IP协议即是Internet协议,使Internet成为一个允许连接不同类型的计算机和不同操作系统的网络。
TCP协议,建立一个连接,用于发送和接受数据的虚拟链路。
下图显示了TCP协议控制两个通信实体互相通信的示意图:
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
在java中,Socket和ServerSocket类库位于java .net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。
这里可以参考疯狂android讲义的第13章内容。
二、下面实现一个简单的socket通信:
java程序,运行java类即可。弄一个简单的服务器:
import java.io.*;
import java.net.*;
public class SimpleServer {
public static void main(String[] args) throws IOException {
// 创建一个ServerSocket,用于监听客户端socket的连接请求
ServerSocket server = new ServerSocket(30001);
// 采用循环方式不断接受来自客户端的请求
while (true) {
// 每当接受到客户端Socket的请求,服务器端也对应产生一个Socket
Socket s = server.accept();
//获取输出流
writer.flush();
writer.close();*/
//通过输出流 向socket中写数据
OutputStream os=s.getOutputStream();
os.write("你好,我是服务器".getBytes("utf-8"));
os.close();
s.close();
}
}
}
再用建立一个android应用,使用socket与制定端口连接,获取数据等。
simpleClient.java
package com.example.simplecilent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.EditText;
public class SimpleClient extends Activity {
EditText show;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show =(EditText)findViewById(R.id.show);
//关闭输入流、socket
try
{
Socket socket = new Socket("10.0.2.2" ,30001);
//将Socket对应的输入流包装成BufferedReader
//将服务器中传过来的数据 通过Inputstream读出来
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
//进行普通IO操作
String line = br.readLine();
show.setText("收到了服务器的数据,内容是:" + line);
br.close();
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
layout的xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/show"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:cursorVisible="false"
android:editable="false" >
</EditText>
</LinearLayout>
实现的效果图:
这里简单的概述一下socket通信大家遇到的几个问题:
1.很多同学,按照疯狂java讲义上面的实现,发现都可以,就是接受不到数据,这里
如果你用的AVD,地址端口应该改为10.0.2.2,就可以正常通信了。
2.很多同学,用的android版本比较高,运行说“Unfortunately,XXX has stopped”,
其实高版本是不支持socket通信的,需要多线程实现,但是这里好像还不是吧,我可以把这个删除:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
试试?
3这个大家都知道:加permission
<uses-permission android:name="android.permission.INTERNET" />
三、多线程
具体也不介绍了,大家看书。
建立一个android应用,ThreadClient
CilentThread.java
package com.example.multithreadclient;
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
{
// 该线程负责处理的Socket
private Socket s;
private Handler handler;
// 该线程所处理的Socket所对应的输入流 收到的数据
BufferedReader br = null;
public ClientThread(Socket s, Handler handler) throws IOException
{
this.s = s;
this.handler = handler;
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
public void run() {
try {
String content = null;
// 不断读取Socket输入流中的内容。
while ((content = br.readLine()) != null) {
// 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据
Message msg = new Message();
msg.what = 0x123;
msg.obj = content;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
MainActivity.java
package com.example.multithreadclient;
import java.io.OutputStream;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
// 定义界面上的两个文本框
EditText input, show;
// 定义界面上的一个按钮
Button send;
OutputStream os;
Handler handler;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
show = (EditText) findViewById(R.id.show);
Socket s;
handler = new Handler() {
@Override
public void handleMessage(Message msg)
{
// 如果消息来自于子线程
if (msg.what == 0x123)
{
// 将读取的内容追加显示在文本框中
show.append("\n" + msg.obj.toString());
}
}
};
try
{
s = new Socket("10.0.2.2", 30006);
// 客户端启动ClientThread线程不断读取来自服务器的数据
new Thread(new ClientThread(s, handler)).start(); // ①
os = s.getOutputStream();
} catch (Exception e) {
e.printStackTrace();
}
send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try
{
// 将用户在文本框内输入的内容写入网络
os.write((input.getText().toString()+"\r\n")
.getBytes("utf-8"));
// 清空input文本框
input.setText("");
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
布局文件 xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<!-- 定义一个文本框,它用于接受用户的输入 -->
<EditText
android:id="@+id/input"
android:layout_width="240px"
android:layout_height="wrap_content" />
<Button
android:id="@+id/send"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="8px"
android:text="send" />
</LinearLayout>
<!-- 定义一个文本框,它用于显示来自服务器的信息 -->
<EditText
android:id="@+id/show"
android:layout_width="fill_parent"
android:layout_height="67dp"
android:cursorVisible="false"
android:editable="false"
android:gravity="top" />
</LinearLayout>
java类 建立一个服务器
MySerer.java
import java.net.*;
import java.io.*;
import java.util.*;
public class MyServer {
// 定义保存所有Socket的ArrayList
public static ArrayList<Socket> socketList = new ArrayList<Socket>();
public static void main(String[] args) throws IOException
{
ServerSocket ss = new ServerSocket(30006);
while (true)
{
// 此行代码会阻塞,将一直等待别人的连接
Socket s = ss.accept();
socketList.add(s);
// 每当客户端连接后启动一条ServerThread线程为该客户端服务 将socket s传过去
new Thread(new ServerThread(s)).start();
}
}
}
ServerThread.java
import java.io.*;
import java.net.*;
import java.util.*;
//负责处理每个线程通信的线程类
public class ServerThread implements Runnable {
// 定义当前线程所处理的Socket
Socket s = null;
// 该线程所处理的Socket所对应的输入流
BufferedReader br = null;
//socket s调用
public ServerThread(Socket s) throws IOException
{
this.s = s;
// 初始化该Socket对应的输入流 将传过来的socket中的数据读出来
br = new BufferedReader(new InputStreamReader(s.getInputStream(),
"utf-8")); // ②
}
public void run() {
try {
String content = null;
// 采用循环不断从Socket中读取客户端发送过来的数据
while ((content = readFromClient()) != null) {
// 遍历socketList中的每个Socket,
// 将读到的内容向每个Socket发送一次
for (Socket s : MyServer.socketList) {
OutputStream os = s.getOutputStream();
os.write((content + "\n").getBytes("utf-8"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 定义读取客户端数据的方法
private String readFromClient() {
try
{
return br.readLine();
}
// 如果捕捉到异常,表明该Socket对应的客户端已经关闭
catch (IOException e) {
// 删除该Socket。
MyServer.socketList.remove(s); // ①
}
return null;
}
}
具体效果图
文章具体参考:《疯狂android讲义》,问题上面已经说过。
好了,小菜鸟初学android,还请指教。