转载

android 之TCP客户端编程

吸取教训!!!本来花了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>

看看布局界面

android 之TCP客户端编程

接着开始编写功能程序

android 之TCP客户端编程

android 之TCP客户端编程

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

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

android 之TCP客户端编程

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

Socket (InetAddressaddress, int port) 

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

地址的指定端口号。

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

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

android 之TCP客户端编程

那么

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

android 之TCP客户端编程

android 之TCP客户端编程

android 之TCP客户端编程

android 之TCP客户端编程

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

android 之TCP客户端编程

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

android 之TCP客户端编程

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

android 之TCP客户端编程

按钮事件改为

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();

}

}

}

你可以试一试了

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

android 之TCP客户端编程

先贴代码

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

android 之TCP客户端编程

android 之TCP客户端编程

所以才有了

// 获取输出流

OutputStream outputStream = socket.getOutputStream();

// 发送数据

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

android 之TCP客户端编程

android 之TCP客户端编程

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

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

// 接收线程

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: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>

MainActivity.java源码

package com.wifi123;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

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 {

boolean isConnect=true;//连接还是断开

Button ConnectButton;//定义连接按钮

Button SendButton;//定义发送按钮

EditText IPEditText;//定义ip输入框

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

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

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

Socket socket = null;//定义socket

private OutputStream outputStream=null;//定义输出流

private InputStream inputStream=null;//定义输入流

@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);//获得端口文本框按钮对象

MsgEditText = (EditText) findViewById(R.id.Send_ET);//获得发送消息文本框对象

RrceiveEditText = (EditText) findViewById(R.id.Receive_ET);//获得接收消息文本框对象

}

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();

}

}

//连接线程

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();

}

}

}

//接收线程

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();

}

}

}

}

原文  http://www.cnblogs.com/yangfengwu/p/5212570.html
正文到此结束
Loading...