TCP socket Android客户端 Python服务端

写在前面的话:每一个实例的代码都会附上相应的代码片或者图片,保证代码完整展示在博客中。最重要的是保证例程的完整性!!!方便自己也方便他人~欢迎大家交流讨论~

今天又写了一篇Android客户端,是为了和前一篇的Python服务端进行传输,这一篇只写了这两个的通信,传输文件的操作还在学习中orz……

Android客户端

新建项目

名为client主要文件如下图
这里写图片描述

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
//第3个一般没什么用……因为在Android Studio中给我加了红色的波浪,但又不影响运行
//大家可以试一下如果没有第3个会不会报错
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

MainActivity

package com.example.administrator.client;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.button1)Button button1;
    @BindView(R.id.editText)EditText editText;
    private static final int port=12567;//connection另一端的端口
    //hostip写服务端的IP
    private static final String hostip="*****";//connection另一端的ip

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }
    @OnClick(R.id.button1)
    public void runtcpClient(){
        Log.i("Client","按钮监听事件有效");
        Thread thread=new Thread(){
            @Override
            public void run(){ tcpClient();}
        };
        thread.start();
    }
    private void tcpClient(){
        try{
            Socket socketClient = new Socket(hostip, port);
            Log.i("Client","新建套接字有效");
            BufferedReader in=new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
            BufferedWriter out=new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
            String outMsg = "TCP connecting to " + port + System.getProperty("line.separator");//发出的数据
            Log.i("Client","得到发出数据");
            out.write(outMsg);//发送数据
            Log.i("Client","发送数据有效");
            out.flush();
            Log.i("TcpClient", "sent: " + outMsg);
            String inMsg = in.readLine() + System.getProperty("line.separator");//服务器返回的数据
            Log.i("TcpClient", "received: " + inMsg);
            socketClient.close();
        }catch (UnknownHostException e){e.printStackTrace();}
        catch (IOException e){e.printStackTrace();}
    }
}

activity_main.xml

布局太简单了。就一个Button,我就不放展示图了

<?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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/button1_name"
        android:id="@+id/button1"/>
 </LinearLayout>

strings.xml

添加<string name="button1_name">client</string>

Python服务端

import socket
BUFSIZE=4096
tcpServerSocket=socket.socket()#创建socket对象
hostname= socket.gethostname()#获取本地主机名
sysinfo = socket.gethostbyname_ex(hostname)
hostip=sysinfo[2][0]
port=12567#设置端口
tcpServerSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)#让端口可以复用
tcpServerSocket.bind((hostip,port))#将地址与套接字绑定,且套接字要求是从未被绑定过的
tcpServerSocket.listen(5)#代办事件中排队等待connect的最大数目
while True:
    print("等待连接")
    #建立客户端连接,接受connection,返回两个参数,c是该connection上可以发送和接收数据的新套接字对象
    #addr是与connection另一端的套接字绑定的地址
    clientSocket, addr = tcpServerSocket.accept()  
    print ('连接地址:', addr)
    while True:
        data=clientSocket.recv(BUFSIZE).decode()
        if not data:
            break
        #向客户端表示接收到数据
        str='来自服务端的消息!'
        clientSocket.send(str.encode())#字符串编码为字节
    #套接字在垃圾收集garbage-collected时会自动close
    #close关闭该connection上的资源但不一定马上断开connection
    #想要立即断开connection,要先调用shutdown再close
    clientSocket.close() # 关闭连接
tcpServerSocket.close()

执行结果

和python服务端的通信结果
这里写图片描述
在cmd中输入netstat -a可查看当前tcp的状况,左边是本机地址,右边是外部地址,如下
是我的服务端打开从监听到和客户端建立连接的过程
这里写图片描述

有坑请注意!

问题1:原来gethostname得到的IP是虚拟机的IP,因为我的电脑安装了虚拟机,而且我发现之前一篇Python客户端服务端TCP传输套接字都是用的那个IP运行的很正常,但是现在客户端是Android用那个IPAndroid端会报出ETIMEOUT的错误
这里写图片描述
解决方法:因为我网上查了半天也不知道怎么解决,而且虚拟机那个IP经常会换,这意味着每次都要查IP然后改到Android非常费事而且不实际,所以就不用那个IP了,换成用本机IP(如果有什么解决方法麻烦大家告诉我orz……,谢谢了)
问题2: IPython console报错了个winerror:计算机积极地阻拦什么的,在Android端也有EREFUSED什么的
解决方法:打开控制面板——windows防火墙——点击如下图红框处——找到安全套接字隧道协议,打勾,确定
这里写图片描述
问题3:下图错误直指data=clientSocket.recv(BUFSIZE).decode()这句代码
这里写图片描述
解决方法:但是我查了一下clientSocket的type,分明就是套接字类型。原因是我把clientSocket.close() # 关闭连接放在第二个while循环中了,上面代码中已更正。

猜你喜欢

转载自blog.csdn.net/Leo_Huang720/article/details/81676538