最近,做项目需要使用Android(客户端)与Linux(服务器端)进行数据通信,这学期也刚好学习了Linux网络编程的一些知识。所以,实现了一个小Demo,供有需要的朋友参考一下。
客户端向服务器端发送字符串数据,服务器收到客户端的数据显示在Linux终端上,并往客户端回发接收到的数据。客户端把发往服务器端的数据与接收到的数据都显示在一个TextView上面。
Linux服务器端:
Android客户端:
首先,有几个小问题要注意一下:
1. 在Android应用程序需要使用Tcp协议进行通信时,需要在AndroidManifest.xml中添加以下权限:
uses-permission android:name=”android.permission.INTERNET”
2. 在真机上面运行调试程序时,要保证手机能Ping通Linux服务器端的IP地址。
3. Android客户端接收数据,最好开一个线程来接收数据,因为是接收数据的read()方法是阻塞式的方法。
Linux服务器端:(Server.c)
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 8888 //服务器端监听端口号
#define MAX_BUFFER 1024 //数据缓冲区最大值
int main()
{
struct sockaddr_in server_addr, client_addr;
int server_sockfd, client_sockfd;
int size, write_size;
char buffer[MAX_BUFFER];
if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) //创建Socket
{
perror("Socket Created Failed!\n");
exit(1);
}
printf("Socket Create Success!\n");
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
bzero(&(server_addr.sin_zero), 8);
int opt = 1;
int res = setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //设置地址复用
if (res < 0)
{
perror("Server reuse address failed!\n");
exit(1);
}
if (bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) //绑定本地地址
{
perror("Socket Bind Failed!\n");
exit(1);
}
printf("Socket Bind Success!\n");
if (listen(server_sockfd, 5) == -1) //监听
{
perror("Listened Failed!\n");
exit(1);
}
printf("Listening ....\n");
socklen_t len = sizeof(client_addr);
printf("waiting connection...\n");
if ((client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len)) == -1) //等待客户端连接
{
perror("Accepted Failed!\n");
exit(1);
}
printf("connection established!\n");
printf("waiting message...\n");
while (1)
{
memset(buffer, 0, sizeof(buffer)); //清空数据缓冲区
if ((size = read(client_sockfd, buffer, MAX_BUFFER)) == -1) //读取客户端的数据
{
perror("Recv Failed!\n");
exit(1);
}
if (size != 0)
{
buffer[size] = '\0';
printf("Recv msg from client: %s\n", buffer);
if ((write_size = write(client_sockfd, buffer, MAX_BUFFER)) > 0) //把收到的数据回发给客户端
{
printf("Sent msg to client successfully!\n");
}
}
}
close(client_sockfd); //关闭Socket
close(server_sockfd);
return 0;
}
Android客户端:
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.blog_tcp_demo.MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="地址:"
android:textSize="20dp"
android:layout_width="60dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/edtTxt_Addr"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout> //地址
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="端口:"
android:textSize="20dp"
android:layout_width="60dp"
android:layout_height="40dp" />
<EditText
android:id="@+id/edtTxt_Port"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout> //端口
<ToggleButton
android:id="@+id/tglBtn"
android:textOn="断开"
android:textOff="连接"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> //连接-断开按钮
<ScrollView
android:layout_width="fill_parent"
android:layout_height="300dp"
android:layout_weight="0.86" >
<TextView
android:id="@+id/tv_Msg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Ready...\n" />
ScrollView> //消息显示
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edtTxt_Data"
android:hint="请输入要发送的数据"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_Send"
android:text="发送"
android:textSize="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
LinearLayout> //数据发送
LinearLayout>
LinearLayout>
MainActivity.java:
package com.example.blog_tcp_demo;
import android.content.Intent;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private EditText edtTxt_Addr;
private EditText edtTxt_Port;
private ToggleButton tglBtn;
private TextView tv_Msg;
private EditText edtTxt_Data;
private Button btn_Send;
private TcpClientConnector connector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitWidgets();
connector = TcpClientConnector.getInstance(); //获取connector实例
tglBtn.setOnCheckedChangeListener(new TglBtnCheckedChangeEvents());
btn_Send.setOnClickListener(new ButtonClickEvent());
}
/***
* 控件初始化
*/
private void InitWidgets(){
edtTxt_Addr = (EditText) findViewById(R.id.edtTxt_Addr);
edtTxt_Port = (EditText) findViewById(R.id.edtTxt_Port);
tglBtn = (ToggleButton) findViewById(R.id.tglBtn);
tv_Msg = (TextView) findViewById(R.id.tv_Msg);
edtTxt_Data = (EditText) findViewById(R.id.edtTxt_Data);
btn_Send = (Button) findViewById(R.id.btn_Send);
}
class TglBtnCheckedChangeEvents implements ToggleButton.OnCheckedChangeListener{
@Override
public void onCheckedChanged(CompoundButton btnView, boolean isChecked){
if(btnView == tglBtn){
if(isChecked == true){
//连接Tcp服务器端
//connector.createConnect("172.16.46.41",8888); //调试使用
connector.createConnect(edtTxt_Addr.getText().toString(),Integer.parseInt(edtTxt_Port.getText().toString()));
connector.setOnConnectListener(new TcpClientConnector.ConnectListener() {
@Override
public void onReceiveData(String data) {
//Received Data,do somethings.
tv_Msg.append("Server:"+ data + "\n");
}
});
}else{
try{ //断开与服务器的连接
connector.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}
class ButtonClickEvent implements View.OnClickListener{
public void onClick(View v){
if (v == btn_Send){
//发送数据
try{
connector.send(edtTxt_Data.getText().toString());
tv_Msg.append("Client:"+ edtTxt_Data.getText().toString() + "\n");
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
TcpClientConnector.java:
package com.example.blog_tcp_demo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TcpClientConnector {
private static TcpClientConnector mTcpClientConnector;
private Socket mClient;
private ConnectListener mListener;
private Thread mConnectThread;
public interface ConnectListener {
void onReceiveData(String data);
}
public void setOnConnectListener(ConnectListener listener) {
this.mListener = listener;
}
public static TcpClientConnector getInstance() {
if (mTcpClientConnector == null)
mTcpClientConnector = new TcpClientConnector();
return mTcpClientConnector;
}
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 100:
if (mListener != null) {
mListener.onReceiveData(msg.getData().getString("data"));
}
break;
}
}
};
public void createConnect(final String mSerIP, final int mSerPort) {
if (mConnectThread == null) {
mConnectThread = new Thread(new Runnable() {
@Override
public void run() {
try {
connect(mSerIP, mSerPort);
} catch (IOException e) {
e.printStackTrace();
}
}
});
mConnectThread.start();
}
}
/**
* 与服务端进行连接
*
* @throws IOException
*/
private void connect(String mSerIP, int mSerPort) throws IOException {
if (mClient == null) {
mClient = new Socket(mSerIP, mSerPort);
}
InputStream inputStream = mClient.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
String data = new String(buffer, 0, len);
Message message = new Message();
message.what = 100;
Bundle bundle = new Bundle();
bundle.putString("data", data);
message.setData(bundle);
mHandler.sendMessage(message);
}
}
/**
* 发送数据
*
* @param data 需要发送的内容
*/
public void send(String data) throws IOException {
OutputStream outputStream = mClient.getOutputStream();
outputStream.write(data.getBytes());
}
/**
* 断开连接
*
* @throws IOException
*/
public void disconnect() throws IOException {
if (mClient != null) {
mClient.close();
mClient = null;
}
}
}
其中,Android客户端的代码参考了这位朋友的博客(^__^) ,写得的确很好,给个大写的赞!:Android Socket 通信