AndroidStudioSocket客户端

Android Studio 3.1.4

Build #AI-173.4907809, built on July 24, 2018
JRE: 1.8.0_152-release-1024-b02 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

1.前言

 1 从这个帖子往后,开头声明版本就不用截图了,用复制出来的文字,反正效果一样的
 2 
 3 这次要说的是SocketTcp协议的客户端
 4 
 5 有些小伙伴可能要问了,昨天才到本地注册和登录,今天怎么就开始Socket了,是不是进度太快了
 6 
 7 这个问题,我想说一下哈,我并不是按照教程或者目录啥的做的
 8 
 9 我是对啥感兴趣就做啥,但我也是小白,能学会的东西,对于大家来说没问题的
10 
11 好了,话不多说,开始笔记!Lucky~

2.我们还是先创建一个项目,项目名是TCPclient,布局界面文件名为activity_tcpclient.xml

界面设计最终样式如下

只后的UI会一次比一次复杂,以后就不口头描述了,直接贴xml

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3     xmlns:app="http://schemas.android.com/apk/res-auto"
  4     xmlns:tools="http://schemas.android.com/tools"
  5     android:layout_width="match_parent"
  6     android:layout_height="match_parent"
  7     tools:context=".TCPclient">
  8 
  9     <Button
 10         android:id="@+id/Button"
 11         style="@android:style/Widget.Material.Light.Button.Small"
 12         android:layout_width="175dp"
 13         android:layout_height="49dp"
 14         android:layout_marginBottom="8dp"
 15         android:layout_marginEnd="8dp"
 16         android:layout_marginTop="8dp"
 17         android:onClick="link"
 18         android:text="连 接 服 务 器"
 19         app:layout_constraintBottom_toBottomOf="parent"
 20         app:layout_constraintEnd_toEndOf="parent"
 21         app:layout_constraintHorizontal_bias="0.96"
 22         app:layout_constraintStart_toStartOf="parent"
 23         app:layout_constraintTop_toTopOf="parent"
 24         app:layout_constraintVertical_bias="0.593" />
 25 
 26     <EditText
 27         android:id="@+id/portEdit"
 28         android:layout_width="245dp"
 29         android:layout_height="43dp"
 30         android:layout_marginBottom="8dp"
 31         android:layout_marginEnd="16dp"
 32         android:layout_marginStart="8dp"
 33         android:layout_marginTop="156dp"
 34         android:ems="10"
 35         android:inputType="textPersonName"
 36         android:text="80"
 37         app:layout_constraintBottom_toBottomOf="parent"
 38         app:layout_constraintEnd_toEndOf="parent"
 39         app:layout_constraintHorizontal_bias="1.0"
 40         app:layout_constraintStart_toStartOf="parent"
 41         app:layout_constraintTop_toTopOf="parent"
 42         app:layout_constraintVertical_bias="0.016" />
 43 
 44     <TextView
 45         android:layout_width="145dp"
 46         android:layout_height="51dp"
 47         android:layout_marginStart="16dp"
 48         android:fontFamily="casual"
 49         android:text="TcpClient"
 50         android:textSize="30sp"
 51         app:layout_constraintBottom_toBottomOf="parent"
 52         app:layout_constraintHorizontal_bias="0.051"
 53         app:layout_constraintLeft_toLeftOf="parent"
 54         app:layout_constraintRight_toRightOf="parent"
 55         app:layout_constraintStart_toStartOf="parent"
 56         app:layout_constraintTop_toTopOf="parent"
 57         app:layout_constraintVertical_bias="0.029" />
 58 
 59     <TextView
 60         android:id="@+id/textView"
 61         android:layout_width="96dp"
 62         android:layout_height="37dp"
 63         android:layout_marginBottom="8dp"
 64         android:layout_marginEnd="8dp"
 65         android:layout_marginStart="16dp"
 66         android:layout_marginTop="8dp"
 67         android:text="IP、域名"
 68         android:textAlignment="center"
 69         android:textSize="22sp"
 70         app:layout_constraintBottom_toBottomOf="parent"
 71         app:layout_constraintEnd_toEndOf="parent"
 72         app:layout_constraintHorizontal_bias="0.0"
 73         app:layout_constraintStart_toStartOf="parent"
 74         app:layout_constraintTop_toTopOf="parent"
 75         app:layout_constraintVertical_bias="0.159" />
 76 
 77     <TextView
 78         android:id="@+id/textView2"
 79         android:layout_width="96dp"
 80         android:layout_height="37dp"
 81         android:layout_marginBottom="8dp"
 82         android:layout_marginEnd="8dp"
 83         android:layout_marginStart="16dp"
 84         android:layout_marginTop="8dp"
 85         android:text="端口"
 86         android:textAlignment="center"
 87         android:textSize="22sp"
 88         app:layout_constraintBottom_toBottomOf="parent"
 89         app:layout_constraintEnd_toEndOf="parent"
 90         app:layout_constraintHorizontal_bias="0.0"
 91         app:layout_constraintStart_toStartOf="parent"
 92         app:layout_constraintTop_toTopOf="parent"
 93         app:layout_constraintVertical_bias="0.3" />
 94 
 95     <TextView
 96         android:id="@+id/textView3"
 97         android:layout_width="96dp"
 98         android:layout_height="37dp"
 99         android:layout_marginBottom="8dp"
100         android:layout_marginEnd="8dp"
101         android:layout_marginStart="16dp"
102         android:layout_marginTop="8dp"
103         android:text="发送数据"
104         android:textAlignment="center"
105         android:textSize="22sp"
106         app:layout_constraintBottom_toBottomOf="parent"
107         app:layout_constraintEnd_toEndOf="parent"
108         app:layout_constraintHorizontal_bias="0.0"
109         app:layout_constraintStart_toStartOf="parent"
110         app:layout_constraintTop_toTopOf="parent"
111         app:layout_constraintVertical_bias="0.45" />
112 
113     <EditText
114         android:id="@+id/IPEdit"
115         android:layout_width="245dp"
116         android:layout_height="43dp"
117         android:layout_marginBottom="8dp"
118         android:layout_marginEnd="16dp"
119         android:layout_marginStart="8dp"
120         android:layout_marginTop="88dp"
121         android:ems="10"
122         android:inputType="textPersonName"
123         android:text="127.0.0.1"
124         app:layout_constraintBottom_toBottomOf="parent"
125         app:layout_constraintEnd_toEndOf="parent"
126         app:layout_constraintHorizontal_bias="1.0"
127         app:layout_constraintStart_toStartOf="parent"
128         app:layout_constraintTop_toTopOf="parent"
129         app:layout_constraintVertical_bias="0.004" />
130 
131     <EditText
132         android:id="@+id/dataEdit"
133         android:layout_width="245dp"
134         android:layout_height="43dp"
135         android:layout_marginBottom="8dp"
136         android:layout_marginEnd="16dp"
137         android:layout_marginStart="8dp"
138         android:layout_marginTop="156dp"
139         android:ems="10"
140         android:inputType="textPersonName"
141         android:text="GET /index.html HTTP/1.1"
142         app:layout_constraintBottom_toBottomOf="parent"
143         app:layout_constraintEnd_toEndOf="parent"
144         app:layout_constraintHorizontal_bias="1.0"
145         app:layout_constraintStart_toStartOf="parent"
146         app:layout_constraintTop_toTopOf="parent"
147         app:layout_constraintVertical_bias="0.23" />
148 
149     <Button
150         android:id="@+id/button"
151         style="@android:style/Widget.Material.Light.Button.Small"
152         android:layout_width="175dp"
153         android:layout_height="49dp"
154         android:layout_marginBottom="8dp"
155         android:layout_marginEnd="8dp"
156         android:layout_marginTop="8dp"
157         android:onClick="play"
158         android:text="发 送 数 据"
159         app:layout_constraintBottom_toBottomOf="parent"
160         app:layout_constraintEnd_toEndOf="parent"
161         app:layout_constraintHorizontal_bias="0.084"
162         app:layout_constraintStart_toStartOf="parent"
163         app:layout_constraintTop_toTopOf="parent"
164         app:layout_constraintVertical_bias="0.593" />
165 
166     <EditText
167         android:id="@+id/editText"
168         android:layout_width="354dp"
169         android:layout_height="177dp"
170         android:layout_marginBottom="8dp"
171         android:layout_marginTop="24dp"
172         android:ems="10"
173         android:inputType="textMultiLine"
174         app:layout_constraintBottom_toBottomOf="parent"
175         app:layout_constraintEnd_toEndOf="parent"
176         app:layout_constraintHorizontal_bias="0.513"
177         app:layout_constraintStart_toStartOf="parent"
178         app:layout_constraintTop_toTopOf="parent"
179         app:layout_constraintVertical_bias="0.977" />
180 
181 
182 </android.support.constraint.ConstraintLayout>

3.首先我们得给程序增加两条权限,打开AndroidManifest.xml文件

加入两条:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

一定不要加错了位置~

3.打开TCPclient项目java文件开始码代码

  1 package com.shawna.tcpclient;
  2 
  3 import android.content.DialogInterface;
  4 import android.support.v7.app.AlertDialog;
  5 import android.support.v7.app.AppCompatActivity;
  6 import android.os.Bundle;
  7 import android.view.View;
  8 import android.widget.Button;
  9 import android.widget.EditText;
 10 
 11 import java.io.InputStream;
 12 import java.io.OutputStream;
 13 import java.net.InetAddress;
 14 import java.net.Socket;
 15 
 16 public class TCPclient extends AppCompatActivity {
 17 
 18     EditText iptoedit;//ip编辑框对象
 19     EditText porttoedit;//端口编辑框对象
 20     EditText datatoedit;//数据编辑框对象
 21     Button Button;//连接服务器按钮对象
 22     EditText edittotext;//接收的数据显示编辑框对象
 23     Socket Socket = null;//Socket
 24     boolean buttontitle = true;//定义一个逻辑变量,用于判断连接服务器按钮状态
 25     boolean RD = false;//用于控制读数据线程是否执行
 26 
 27     OutputStream OutputStream = null;//定义数据输出流,用于发送数据
 28     InputStream InputStream = null;//定义数据输入流,用于接收数据
 29 
 30     @Override
 31     protected void onCreate(Bundle savedInstanceState) {
 32         super.onCreate(savedInstanceState);
 33         setContentView(R.layout.activity_tcpclient);
 34 
 35         iptoedit = (EditText)findViewById(R.id.IPEdit);//获取ip地址编辑框对象
 36         porttoedit = (EditText)findViewById(R.id.portEdit);//获取端口编辑框对象
 37         datatoedit = (EditText)findViewById(R.id.dataEdit);//获取欲发送的数据编辑框对象
 38         Button = (Button)findViewById(R.id.Button);//获取连接服务器按钮对象
 39         edittotext = (EditText)findViewById(R.id.editText);//获取接收数据显示编辑框对象
 40 
 41     }
 42 
 43     //发送数据按钮按下
 44     public void play(View view){
 45         //验证编辑框用户输入内容是否合法
 46         if (thisif()) {
 47             //启动一个新的线程,用于发送数据
 48             ThreadSendData t1 = new ThreadSendData();
 49             t1.start();
 50         } else{
 51             //这个地方默认是没有反应,可以自行修改成信息框提示
 52             return;
 53         }
 54     }
 55 
 56     //连接服务器按钮按下
 57     public void link(View view){
 58         //判断按钮状态
 59         if (buttontitle == true){
 60             //如果按钮没有被按下,则按钮状态改为按下
 61             buttontitle = false;
 62             //读数据线程可以执行
 63             RD = true;
 64             //并创建一个新的线程,用于初始化socket
 65             Connect_Thread Connect_thread = new Connect_Thread();
 66             Connect_thread.start();
 67             //改变按钮标题
 68             Button.setText("断 开 连 接");
 69         }else{
 70             //如果按钮已经被按下,则改变按钮标题
 71             Button.setText("连 接 服 务 器");
 72             //储存状态的变量反转
 73             buttontitle = true;
 74             try{
 75                 //取消socket
 76                 Socket.close();
 77                 //socket设置为空
 78                 Socket = null;
 79                 //读数据线程不执行
 80                 RD = false;
 81             }catch (Exception e){
 82                 //如果想写的严谨一点,可以自行改动
 83                 e.printStackTrace();
 84             }
 85         }
 86     }
 87 
 88     //用线程创建Socket连接
 89     class Connect_Thread extends Thread{
 90         public void run(){
 91             //定义一个变量用于储存ip
 92             InetAddress ipAddress;
 93             try {
 94                 //判断socket的状态,防止重复执行
 95                 if (Socket == null) {
 96                     //如果socket为空则执行
 97                         //获取输入的IP地址
 98                     ipAddress = InetAddress.getByName(iptoedit.getText().toString());
 99                         //获取输入的端口
100                     int port = Integer.valueOf(porttoedit.getText().toString());
101                     //新建一个socket
102                     Socket = new Socket(ipAddress, port);
103                     //获取socket的输入流和输出流
104                     InputStream = Socket.getInputStream();
105                     OutputStream = Socket.getOutputStream();
106 
107                     //新建一个线程读数据
108                     ThreadReadData t1 = new ThreadReadData();
109                     t1.start();
110                 }
111             } catch (Exception e) {
112                 //如果有错误则在这里返回
113                 e.printStackTrace();
114             }
115         }
116     }
117 
118     //用线程执行读取服务器发来的数据
119     class ThreadReadData extends Thread{
120         public void run() {
121             //定义一个变量用于储存服务器发来的数据
122             String textdata;
123             //根据RD变量的值判断是否执行读数据
124             while (RD) {
125                 try {
126                     //定义一个字节集,存放输入的数据,缓存区大小为2048字节
127                     final byte[] ReadBuffer = new byte[2048];
128                     //用于存放数据量
129                     final int ReadBufferLengh;
130 
131                     //从输入流获取服务器发来的数据和数据宽度
132                         //ReadBuffer为参考变量,在这里会改变为数据
133                         //输入流的返回值是服务器发来的数据宽度
134                     ReadBufferLengh = InputStream.read(ReadBuffer);
135 
136                     //验证数据宽度,如果为-1则已经断开了连接
137                     if (ReadBufferLengh == -1) {
138                         //重新归位到初始状态
139                         RD = false;
140                         Socket.close();
141                         Socket = null;
142                         buttontitle = true;
143                         Button.setText("连 接 服 务 器");
144                     } else {
145                         //如果有数据正常返回则进行处理显示
146 
147                         /*
148                             这个地方有个很大的坑,让我搞了不少的时间
149                             我用其他语言写的Web服务器程序,默认编码是gb2312
150                             AS的默认编码是utf-8
151                             在获取服务器发来的数据的时候,程序已经对这段gb2312的数据进行编码...
152                             至于编码是什么就不知道了
153                             我研究了很长时间,怎么转码也不对,越转越乱
154                             最后测试出来是gb2312编码已经被转码了,我就先恢复gb2312编码
155                             然后转成程序不会乱码的utf-8
156                             如果目标服务器编码是utf8的话就不用转了
157                         */
158 
159                         //先恢复成GB2312编码
160                         textdata = new String(ReadBuffer,0,ReadBufferLengh,"GB2312");//原始编码数据
161                         //转为UTF-8编码后显示在编辑框中
162                         edittotext.setText(new String(textdata.getBytes(),"UTF-8"));
163                     }
164                 } catch (Exception e) {
165                     e.printStackTrace();
166                 }
167             }
168         }
169     }
170 
171     //用线程发送数据
172     class ThreadSendData extends Thread{
173         public void run(){
174             try {
175                 //用输出流发送数据
176                 OutputStream.write(datatoedit.getText().toString().getBytes());
177                 //发送数据之后会自动断开连接,所以,恢复为最初的状态
178                     //有个坑要说一下,因为发送完数据还得等待服务器返回,所以,不能把Socket也注销掉
179                 buttontitle = true;
180                 //改变按钮标题
181                 Button.setText("连 接 服 务 器");
182             }catch (Exception e){
183                 e.printStackTrace();
184             }
185         }
186     }
187 
188     //验证编辑框内容是否合法
189     public boolean thisif (){
190         //定义一个信息框留作备用
191         AlertDialog.Builder message = new AlertDialog.Builder(this);
192         message.setPositiveButton("确定",click1);
193 
194         //分别获取ip、端口、数据这三项的内容
195         String ip = iptoedit.getText().toString();
196         String port = porttoedit.getText().toString();
197         String data = datatoedit.getText().toString();
198 
199         //判断是否有编辑框为空
200         if (ip == null || ip.length() == 0 || port == null || port.length() == 0 || data == null || data.length() == 0){
201             //如果有空则弹出提示
202             message.setMessage("各数据不能为空!");
203             AlertDialog m1 = message.create();
204             m1.show();
205             return false;
206         }else{
207             return true;
208         }
209     }
210 
211     //信息框按钮按下事件
212     public DialogInterface.OnClickListener click1 = new DialogInterface.OnClickListener() {
213         @Override
214         public void onClick(DialogInterface dialog, int which) {
215             dialog.cancel();
216         }
217     };
218 
219 }

4.终于还是在长篇大论下,完成了记录~

5.补充知识点

1 /*
2 
3   Socket在Android4.0版本开始,不能在主线程中使用!
4 
5   一些关键操作,不要忘记增加权限
6 
7   某些命令自带转码效果,一定要注意转码
8 
9 */
 1 //线程的创建与使用
 2     //继承Thread的线程
 3 class 线程名 extends Thread{
 4     public void run(){
 5         //执行的代码
 6     }
 7 }
 8     //使用线程
 9 public void 某个函数名(参数类型 参数名){
10     线程名 自定义名称 = new 线程名();
11     自定义名称.start();
12 }

6.Lucky~

posted @ 2018-08-22 04:33  凌晓纳  阅读(10704)  评论(1编辑  收藏  举报