首页 编程 软件学院 查看内容

android 之TCP客户端编程

2016-2-25 11:07 1958 0

摘要: 吸取教训!!!本来花了5个小时写完了,没想到,,,因为没点上面的自动保存查看一下,全没了,重新写呗关于网络通信:每一台电脑都有自己的ip地址,每台电脑上的网络应用程序都有自己的通信端口,张三的电脑(ip:1 ...

吸取教训!!!本来花了5个小时写完了,没想到,,,因为没点上面的自动保存查看一下,全没了,重新写呗

关于网络通信:每一台电脑都有自己的 ip 地址,每台电脑上的网络应用程序都有自己的通信端口,张三的电脑( ip : 192.168.1.110 )上有一个网络应用程序 A (通信端口 5000 ),李四的电脑( ip : 192.168.1.220 )上有一个网络应用程序 B (通信端口 8000 ),张三给李四发消息,首先你要知道李四的 ip 地址,向指定的 ip (李四ip : 192.168.1.220 )发信息,信息就发到了李四的电脑。再指定一下发送的端口号(通信端口 8000 ),信息就发到了李四电脑的网络应用程序 B 上。

TCP-- 一种网络通信方式而已。分为服务器(网络应用程序)和客户端(网络应用程序), TCP 通信过程,首先打开服务器,监听自己的网络通信端口(假设为 9000),打开客户端,设置好要连接的 ip 地址和服务器的网络通信端口( 9000 ),这样服务器一旦监听到网络通信端口有连接,二者就建立了连接。

好一步一步写程序(最后有源码!!!!!!!)

怎样建立工程就不说了,本来写好了并贴了图,网络一有问题全没了。抱怨一下,博客传图片真麻烦。竟然不支持复制 粘贴。各位朋友有什么方便的方法请告知。

在布局文件里加入两个按钮( button ),一个控制连接,一个控制发送消息;四个输入文本框( edittext ),一个填写发送的信息内容,一个显示服务器发来的消息。一个填写要链接的 ip 地址,一个填写要链接的端口号

布局代码

<RelativeLayout 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"

tools:context="com.wifi123.MainActivity" >

以上都不用管的,软件自动生成的,配置界面的

<!-- 显示的标题:目标 IP 地址 -->

<TextView 

android:textSize="20dp" 字体大小

android:id="@+id/IP_tv" id 号

android:text=" 目标 IP 地址 " 显示的内容

android:layout_width="wrap_content" 宽度随内容而定

android:layout_height="wrap_content" 高度度随内容而定

/>

<!-- 显示的标题:目标端口号 -->

<TextView 

android:textSize="20dp"

android:id="@+id/Port_tv"

android:text=" 目标端口号 "

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@id/IP_tv" 在 <!-- 显示的标题:目标 IP 地址 --> 的下面

android:layout_marginTop="30dp" 离它上面那个组件( <!-- 显示的标题:目标 IP地址 --> )的距离

/>

<!--  用于填写 ip 地址的文本框 -->

<EditText 

android:text="192.168.4.1"

android:id="@+id/ip_ET"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_toRightOf="@id/IP_tv" 在 <!-- 显示的标题:目标 IP 地址 --> 的右面

/>

<!--  用于填写端口号的文本框 -->

<EditText 

android:text="8080"

android:id="@+id/Port_ET"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_toRightOf="@id/Port_tv" 还是在谁谁谁的右面

android:layout_alignBottom="@id/Port_tv" 本元素的下边缘和某元素的的下边缘对齐  

/>

<!--  用于发送信息的文本框 -->

<EditText 

android:id="@+id/Send_ET"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@id/Port_tv" 在某元素的下方

/>

<!--  用于连接的按钮 -->

<Button 

android:text=" 连接 "

android:id="@+id/Connect_Bt"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="Connect_onClick" 设置按钮的动作监听函数,其实有几种写法,就用最简单的一种

android:layout_below="@id/Send_ET" 在某元素的下方

/>

<!--  用于发送信息的按钮 -->

<Button 

android:text=" 发送 "

android:id="@+id/Send_Bt"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="Send_onClick"

android:layout_below="@id/Send_ET"

android:layout_alignParentRight="true"   贴紧父元素的右边缘,指的是整体的界面

/>

<!--  用于接收信息的文本框 -->

<EditText 

android:background="@android:color/darker_gray"

android:id="@+id/Receive_ET"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@id/Connect_Bt"

android:layout_alignParentBottom="true" 贴紧父元素的下边缘  

/>

</RelativeLayout>

看看布局界面

接着开始编写功能程序

先做点击连接按钮就连接服务器

查看 java 的 API 文档,里面封装了专门用于 TCP 客户端通信的类,和方法

里面有一个类 Socket  (客服端),有一个它的构造方法

Socket (InetAddressaddress, int port) 

创建一个流套接字并将其连接到指定  IP 

地址的指定端口号。

意思是 Socket socket = new  Socket (InetAddressaddress, int port) ;// 创建连接地址和端口,就去连接指定的 ip 和端口号去了, address 填 ip 地址, port 填端口号

只不过InetAddress是一个类,我们打开看一下

那么

InetAddress ipAddress = InetAddress.getByName("192.168.4.1");

socket = new Socket(ipAddress, 8080);// 创建连接地址和端口 --------------

就完了,客户端就去连接了

但是 ip 地址和端口被我们定死了,,,,可不好玩,我们就设置成获取 ip 文本框中的 ip ,端口号文本框中的端口号

InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());

int port =Integer.valueOf(PortText.getText().toString());// 获取端口号  

socket = new Socket(ipAddress, port);// 创建连接地址和端口 -------------------

这样就好多了

但是由于在 android 几开始,不允许在主线程里连接服务器,所以只好让按钮点击后启动一个线程里面写上面的东西

package com.wifi123;

import java.net.InetAddress;

import java.net.Socket;

import java.net.UnknownHostException;

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.view.MenuItem;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

public class MainActivity extends Activity {

Button ConnectButton;// 定义连接按钮

Button SendButton;// 定义发送按钮

EditText IPEditText;// 定义 ip 输入框

EditText PortText;// 定义端口输入框

EditText MsgText;// 定义信息输出框

EditText RrceiveText;// 定义信息输入框

Socket socket = null;// 定义 socket

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ConnectButton = (Button) findViewById(R.id.Connect_Bt);// 获得按钮对象

SendButton = (Button) findViewById(R.id.Send_Bt);// 获得按钮对象

IPEditText = (EditText) findViewById(R.id.ip_ET);// 获得 ip 文本框对象

PortText = (EditText) findViewById(R.id.Port_ET);// 获得端口文本框按钮对象

}

public void Connect_onClick(View v) {

// 启动连接线程

Connect_Thread connect_Thread = new Connect_Thread();

connect_Thread.start();

}

class Connect_Thread extends Thread// 继承 Thread

{

public void run()// 重写 run 方法

{

try 

{

if (socket == null) // 如果已经连接上了,就不再执行连接程序

{

// 用 InetAddress 方法获取 ip 地址

InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());

int port =Integer.valueOf(PortText.getText().toString());// 获取端口号  

socket = new Socket(ipAddress, port);// 创建连接地址和端口 ------------------- 这样就好多了

}

catch (Exception e) 

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

对了需要添加两个权限,一个是 wifi 权限,一个是 internet

然后下载到手机因为我的电脑的 ip 为 192.168.1.101 ,所以我把 192.168.4.1 改了, 192.168.4.1 是为了做与 wifi 模块 EPS8266 通信使得

然后打开网络调试助手,点击连接(可以关闭电脑防火墙),然后点击手机上的连接

好接着,连接按钮按一下连接,再按一下断开连接,并且,连接后按钮上显示断开,断开后按钮上显示连接

按钮事件改为

public void Connect_onClick(View v) {

if (isConnect == true) // 标志位  = true 表示连接

{

isConnect = false;// 置为 false

ConnectButton.setText(" 断开 ");// 按钮上显示 -- 断开

// 启动连接线程

Connect_Thread connect_Thread = new Connect_Thread();

connect_Thread.start();

}

else // 标志位  = false 表示退出连接

{

isConnect = true;// 置为 true

ConnectButton.setText(" 连接 ");// 按钮上显示连接

try 

{

socket.close();// 关闭连接

socket=null;

catch (IOException e) 

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

你可以试一试了

接着写点击发送按钮把发送信息文本框的内容发送出去

先贴代码

public void Send_onClick(View v) {

try 

{

// 获取输出流

outputStream = socket.getOutputStream();

// 发送数据

outputStream.write(MsgEditText.getText().toString().getBytes());

//outputStream.write("0".getBytes());

catch (Exception e) 

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

看看 javaAPI

所以才有了

// 获取输出流

OutputStream outputStream = socket.getOutputStream();

// 发送数据

outputStream.write(MsgEditText.getText().toString().getBytes());

接收数据并在信息框显示出来

创建一个接收线程,在连接线程成功建立连接后启动接收线程

// 接收线程

class Receive_Thread extends Thread

{

public void run()// 重写 run 方法

{

try

{

while (true)

{

final byte[] buffer = new byte[1024];// 创建接收缓冲区

inputStream = socket.getInputStream();

final int len = inputStream.read(buffer);// 数据读出来,并且返回数据的长度

runOnUiThread(new Runnable()// 不允许其他线程直接操作组件,用提供的此方法可以

{

public void run()

{

// TODO Auto-generated method stub

RrceiveEditText.setText(new String(buffer,0,len));

}

});

}

}

catch (IOException e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

// 连接线程

class Connect_Thread extends Thread// 继承 Thread

{

public void run()// 重写 run 方法

{

try

{

if (socket == null)

{

// 用 InetAddress 方法获取 ip 地址

InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());

int port =Integer.valueOf(PortText.getText().toString());// 获取端口号 

socket = new Socket(ipAddress, port);// 创建连接地址和端口 ------------------- 这样就好多了

// 在创建完连接后启动接收线程

Receive_Thread receive_Thread = new Receive_Thread();

receive_Thread.start();

}

}

catch (Exception e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

下面贴全部源码

activity_mian.xml源码

<RelativeLayout 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"

tools:context="com.wifi123.MainActivity" >

<!--显示的标题:目标IP地址-->

<TextView

android:textSize="20dp"

android:id="@+id/IP_tv"

android:text="目标IP地址"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

/>

<!--显示的标题:目标端口号-->

<TextView

android:textSize="20dp"

android:id="@+id/Port_tv"

android:text="目标端口号"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@id/IP_tv"

android:layout_marginTop="30dp"

/>

<!-- 用于填写ip地址的文本框-->

<EditText

android:text="192.168.1.101"

android:id="@+id/ip_ET"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_toRightOf="@id/IP_tv"

/>

<!-- 用于填写端口号的文本框-->

<EditText

android:text="8080"

android:id="@+id/Port_ET"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layo

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除
1

路过

雷人

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

  • 路过

    匿名

最新评论

返回顶部