android 之TCP客戶端編程

補充,因爲這篇文章是本身入門的時候寫的,隨着Android系統的升級可能有發送須要在任務html

中進行,若有問題請百度 threadjava

或者看下面連接的文章android

https://www.cnblogs.com/yangfengwu/category/1187355.html服務器

 

 

吸收教訓!!!原本花了5個小時寫完了,沒想到,,,由於沒點上面的自動保存查看一下,全沒了,從新寫唄網絡

關於網絡通訊:每一臺電腦都有本身的ip地址,每臺電腦上的網絡應用程序都有本身的通訊端口,張三的電腦(ip192.168.1.110)上有一個網絡應用程序A(通訊端口5000),李四的電腦(ip192.168.1.220)上有一個網絡應用程序B(通訊端口8000),張三給李四發消息,首先你要知道李四的ip地址,向指定的ip(李四ip192.168.1.220)發信息,信息就發到了李四的電腦。再指定一下發送的端口號(通訊端口8000),信息就發到了李四電腦的網絡應用程序B上。app

TCP--一種網絡通訊方式而已。分爲服務器(網絡應用程序)和客戶端(網絡應用程序),TCP通訊過程,首先打開服務器,監聽本身的網絡通訊端口(假設爲9000),打開客戶端,設置好要鏈接的ip地址和服務器的網絡通訊端口(9000),這樣服務器一旦監聽到網絡通訊端口有鏈接,兩者就創建了鏈接。socket

好一步一步寫程序(最後有源碼!!!!!!!)ide

怎樣創建工程就不說了,原本寫好了並貼了圖,網絡一有問題全沒了。抱怨一下,博客傳圖片真麻煩。居然不支持複製  粘貼。各位朋友有什麼方便的方法請告知。函數

 

在佈局文件里加入兩個按鈕(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(); } } }}

相關文章
相關標籤/搜索