标签:java4android socket server client
本节主要介绍Socket编程,发现Java里面的socket编程和C语言的还是有一些不一样,比如TCP socket ,在Java中区分了serverSocket。不过原理都一样,在流程处理上也非常相似,所以,理解起来并不难。我们会先从基础说起,从如何建立socket连接,到如何实现一个合理的设计例如在android中,我们发送一条消息,然后监听一个回复,如何做到不卡死UI,本文将会由浅入深的为大家呈现一个相对完整的android socket编程。
在进入Java 的socket编程之前,我们从原理上切入,然后提及相应的代码说明。
Socket可以说是一种针对网络的抽象,应用通过它可以来针对网络读写数据。就像通过一个文件的file handler就可以都写数据到存储设备上一样。根据TCP协议和UDP协议的不同,在网络编程方面就有面向两个协议的不同socket,一个是面向字节流的一个是面向报文的。

TCP主要是面向连接的协议,它包含有建立和拆除连接,保证数据流的顺序和正确性等功能。每次对TCP中间的数据操作相当于对一个数据流进行访问。它最典型的特征就是那三次握手的建立连接过程。TCP的连接建立和撤销过程如下图:

这个流程的典型示例代码如下:
//1. 构造ServerSocket实例,指定服务端口。
ServerSocket servSock = new ServerSocket(servPort);
while(true)
{
// 2.调用accept方法,建立和客户端的连接
Socket clntSock = servSock.accept();
SocketAddress clientAddress =
clntSock.getRemoteSocketAddress();
System.out.println("Handling client at " + clientAddress);
// 3. 获取连接的InputStream,OutputStream来进行数据读写
InputStream in = clntSock.getInputStream();
OutputStream out = clntSock.getOutputStream();
while((recvMsgSize = in.read(receiveBuf)) != -1)
{
out.write(receiveBuf, 0, recvMsgSize);
}
// 4.操作结束,关闭socket.
clntSock.close();
}
try
{ file://建立服务器
ServerSocket server = new ServerSocket(9998);
int i=1;
for(;;)
{
<span style="white-space:pre"> </span>Socket incoming = server.accept();
<span style="white-space:pre"> </span>new ServerThread(incoming,i).start(); //开启线程来处理客户端的请求
<span style="white-space:pre"> </span>i++;
}
}catch (IOException ex){ ex.printStackTrace(); } // 1.根据指定的server地址和端口,建立socket连接。 Socket socket = new Socket(server, servPort); // 2. 根据socket实例获取InputStream, OutputStream进行数据读写。 InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); out.write(data); //3.操作结束,关闭socket. socket.close();
package com.nan.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MyClientActivity extends Activity
{
private EditText mEditText = null;
private Button connectButton = null;
private Button sendButton = null;
private TextView mTextView = null;
private Socket clientSocket = null;
private OutputStream outStream = null;
private Handler mHandler = null;
private ReceiveThread mReceiveThread = null;
private boolean stop = true;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mEditText = (EditText)this.findViewById(R.id.edittext);
mTextView = (TextView)this.findViewById(R.id.retextview);
connectButton = (Button)this.findViewById(R.id.connectbutton);
sendButton = (Button)this.findViewById(R.id.sendbutton);
sendButton.setEnabled(false);
//连接按钮监听
connectButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
try
{
//实例化对象并连接到服务器
clientSocket = new Socket("113.114.170.246",8888);
}
catch (UnknownHostException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
displayToast("连接成功!");
//连接按钮使能
connectButton.setEnabled(false);
//发送按钮使能
sendButton.setEnabled(true);
mReceiveThread = new ReceiveThread(clientSocket);
stop = false;
//开启线程
mReceiveThread.start();
}
});
//发送数据按钮监听
sendButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
byte[] msgBuffer = null;
//获得EditTex的内容
String text = mEditText.getText().toString();
try {
//字符编码转换
msgBuffer = text.getBytes("GB2312");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
//获得Socket的输出流
outStream = clientSocket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//发送数据
outStream.write(msgBuffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//清空内容
mEditText.setText("");
displayToast("发送成功!");
}
});
//消息处理
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
//显示接收到的内容
mTextView.setText((msg.obj).toString());
}
};
}
//显示Toast函数
private void displayToast(String s)
{
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
private class ReceiveThread extends Thread
{
private InputStream inStream = null;
private byte[] buf;
private String str = null;
ReceiveThread(Socket s)
{
try {
//获得输入流
this.inStream = s.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run()
{
while(!stop)
{
this.buf = new byte[512];
try {
//读取输入数据(阻塞)
this.inStream.read(this.buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//字符编码转换
try {
this.str = new String(this.buf, "GB2312").trim();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Message msg = new Message();
msg.obj = this.str;
//发送消息
mHandler.sendMessage(msg);
}
}
}
@Override
public void onDestroy()
{
super.onDestroy();
if(mReceiveThread != null)
{
stop = true;
mReceiveThread.interrupt();
}
}
}package com.nan.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
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.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MyServerActivity extends Activity
{
private TextView ipTextView = null;
private EditText mEditText = null;
private Button sendButton = null;
private TextView mTextView = null;
private OutputStream outStream = null;
private Socket clientSocket = null;
private ServerSocket mServerSocket = null;
private Handler mHandler = null;
private AcceptThread mAcceptThread = null;
private ReceiveThread mReceiveThread = null;
private boolean stop = true;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ipTextView = (TextView)this.findViewById(R.id.iptextview);
mEditText = (EditText)this.findViewById(R.id.sedittext);
sendButton = (Button)this.findViewById(R.id.sendbutton);
sendButton.setEnabled(false);
mTextView = (TextView)this.findViewById(R.id.textview);
//发送数据按钮监听
sendButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
byte[] msgBuffer = null;
//获得EditTex的内容
String text = mEditText.getText().toString();
try {
//字符编码转换
msgBuffer = text.getBytes("GB2312");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
//获得Socket的输出流
outStream = clientSocket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//发送数据
outStream.write(msgBuffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//清空内容
mEditText.setText("");
displayToast("发送成功!");
}
});
//消息处理
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case 0:
{
//显示客户端IP
ipTextView.setText((msg.obj).toString());
//使能发送按钮
sendButton.setEnabled(true);
break;
}
case 1:
{
//显示接收到的数据
mTextView.setText((msg.obj).toString());
break;
}
}
}
};
mAcceptThread = new AcceptThread();
//开启监听线程
mAcceptThread.start();
}
//显示Toast函数
private void displayToast(String s)
{
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
private class AcceptThread extends Thread
{
@Override
public void run()
{
try {
//实例化ServerSocket对象并设置端口号为8888
mServerSocket = new ServerSocket(8888);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}while(1)
{ try {
//等待客户端的连接(阻塞)
clientSocket = mServerSocket.accept();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mReceiveThread = new ReceiveThread(clientSocket);
stop = false;
//开启接收线程
mReceiveThread.start();
Message msg = new Message();
msg.what = 0;
//获取客户端IP
msg.obj = clientSocket.getInetAddress().getHostAddress();
//发送消息
mHandler.sendMessage(msg);
}
}
}
private class ReceiveThread extends Thread
{
private InputStream mInputStream = null;
private byte[] buf ;
private String str = null;
ReceiveThread(Socket s)
{
try {
//获得输入流
this.mInputStream = s.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run()
{
while(!stop)
{
this.buf = new byte[512];
//读取输入的数据(阻塞读)
try {
this.mInputStream.read(buf);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//字符编码转换
try {
this.str = new String(this.buf, "GB2312").trim();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Message msg = new Message();
msg.what = 1;
msg.obj = this.str;
//发送消息
mHandler.sendMessage(msg);
}
}
}
@Override
public void onDestroy()
{
super.onDestroy();
if(mReceiveThread != null)
{
stop = true;
mReceiveThread.interrupt();
}
}
}
UDP和TCP有两个典型的区别,一个就是它不需要建立连接,另外就是它在每次收发的报文都保留了消息的边界。
// 1. 构建DatagramSocket实例,指定本地端口。
DatagramSocket socket = new DatagramSocket(servPort);
// 2. 构建需要收发的DatagramPacket报文
DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
while(true)
{
// 3. 收报文
socket.receive(packet);
System.out.println("Handling client at " + packet.getAddress().getHostAddress()
+ " on port " + packet.getPort());
// 4. 发报文
socket.send(packet);
packet.setLength(ECHOMAX);
}
// 1. 构造UDP DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
// 2。指定timeout时间,防止进入无限等待状态
socket.setSoTimeout(TIMEOUT);
// 3. 构造收发的报文对象
DatagramPacket sendPacket = new DatagramPacket(bytesToSend,
bytesToSend.length, serverAddress, servPort);
DatagramPacket receivePacket =
new DatagramPacket(new byte[bytesToSend.length], bytesToSend.length);
// 4.指定尝试的次数
int tries = 0;
boolean receivedResponse = false;
do
{
socket.send(sendPacket);
try
{
socket.receive(receivePacket);
if(!receivePacket.getAddress().equals(serverAddress))
{
throw new IOException("Received packet from an unknown source");
}
receivedResponse = true;
}
catch(InterruptedIOException e)
{
tries += 1;
System.out.println("Timed out, " + (MAXTRIES - tries) + "");
}
}while((!receivedResponse) && (tries < MAXTRIES));
// 根据是否接收到报文进行反馈
if(receivedResponse)
{
System.out.println("Received: " + new String(receivePacket.getData()));
}
else
{
System.out.println("No response -- giving up.");
}
// 5. 关闭socket
socket.close();Reference:
http://shmilyaw-hotmail-com.iteye.com/blog/1556187
http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html
标签:java4android socket server client
原文地址:http://blog.csdn.net/minimicall/article/details/39206121