android 之TCP客戶端編程


補充,由於這篇文章是自己入門的時候寫的,隨着Android系統的升級可能有發送需要在任務

中進行,如有問題請百度 thread

或者看下面鏈接的文章

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上。

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

}
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM