Android(客户端)与Linux(服务器端)进行TCP数据通信
16lz
2021-01-26
最近,做项目需要使用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:
<?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="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 通信
更多相关文章
- Android基于TCP和URL协议的网络编程示例【附demo源码下载】
- 2012年移动互联网数据报告探讨
- 【Android】SQLiteOpenHelper类(sql语句实现增删改查),封装SQLite
- Android使用SQLITE3 WAL模式
- 每天学习一个Android中的常用框架——2.greenDao
- Android进阶高手(五)之Android聊天室(4)---完结篇
- 常见ACTION的用法
- 对新浪微博android客户端中ListView的实现
- Android智能手机中各种音频场景下的audio data path