android 之TCP客戶端編程

關於網絡通信:每一臺電腦都有自己的ip地址,每臺電腦上的網絡應用程序都有自己的通信端口,張三的電腦(ip192.168.1.110)上有一個網絡應用程序A(通信端口5000),李四的電腦(ip192.168.1.220)上有一個網絡應用程序B(通信端口8000),張三給李四發消息,首先你要知道李四的ip地址,向指定的ip(李四ip192.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>

看看佈局界面

接着開始編寫功能程序

先做點擊連接按鈕就連接服務器

查看javaAPI文檔,裏面封裝了專門用於TCP客戶端通信的類,和方法

裏面有一個類Socket (客服端),有一個它的構造方法

Socket(InetAddress address, int port) 
          創建一個流套接字並將其連接到指定 IP 地址的指定端口號。

意思是Socket socket = new Socket(InetAddress address, int port) ;//創建連接地址和端口,就去連接指定的ip和端口號去了,addressip地址,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

然後下載到手機因爲我的電腦的ip192.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: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();
}

}
}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章