Android中基于socket的網(wǎng)絡(luò)通信

本文介紹編寫一個(gè)使用Socket完成Android客戶端與服務(wù)器端通信的簡(jiǎn)單Demo

詳細(xì)代碼地址:github.com/Baolvlv/LearnAndroid/tree/master/MySocketClient

(1)Socket介紹

Socket,又稱套接字,應(yīng)用通過socket向網(wǎng)絡(luò)發(fā)出請(qǐng)求或應(yīng)答網(wǎng)絡(luò)請(qǐng)求

在java中尺碰,Socket與ServerSocket位于java.net包中挣棕。ServerSocket位于服務(wù)器端汇竭,Socket位于客戶端。連接成功時(shí)穴张,兩端都產(chǎn)生一個(gè)Socket實(shí)例,通過操作這個(gè)實(shí)例完成會(huì)話两曼。兩端的實(shí)例平等皂甘,沒有差別,通過Socket與其子類完成所有操作悼凑。

(2)Sokcet鏈接建立過程

1.服務(wù)器監(jiān)聽 ? ?2.客戶端發(fā)出請(qǐng)求 ? ?3.建立鏈接 ? ?4.通信

(3)Socket的特點(diǎn)

Socket基于Tcp鏈接偿枕,數(shù)據(jù)傳輸有保障

Socket適用于建立長(zhǎng)時(shí)間鏈接

Socket編程通常應(yīng)用于即時(shí)通信

Eclipse中新建java工程,包户辫,類渐夸。

創(chuàng)建ServerSocket對(duì)象,自定義通信端口號(hào)(1-65535)65535最大的16位為二進(jìn)制數(shù)渔欢。

// 構(gòu)造函數(shù)參數(shù)為SerSocket偵聽的端口墓塌,取值1-65535

//隨意取值,使用較大的端口奥额,與預(yù)留端口區(qū)分

try{//創(chuàng)建serverSocket對(duì)象

ServerSocket

serverSocket=newServerSocket(12345);

調(diào)用serverSocket.accept方法苫幢,偵聽客戶端的請(qǐng)求,創(chuàng)建socket垫挨。此方法在客戶端請(qǐng)求之前會(huì)導(dǎo)致線程一直為阻塞狀態(tài)韩肝。當(dāng)accept方法執(zhí)行,socket被賦值九榔,則說明鏈接建立哀峻。

//偵聽客戶端的請(qǐng)求,會(huì)阻塞當(dāng)前線程? block

//accept方法執(zhí)行哲泊,socket被賦值剩蟀,則說明鏈接建立

Socket

socket=serverSocket.accept();

建立連接后,服務(wù)器端彈出對(duì)話框攻旦,使用java swing

//建立鏈接后執(zhí)行喻旷,彈出對(duì)話框,第一個(gè)參數(shù)為父級(jí)容器

JOptionPane.showMessageDialog(

null,"有客戶端鏈接到了本機(jī)的12345端口");

此時(shí)運(yùn)行程序牢屋,程序會(huì)一直運(yùn)行且预,直到客戶端發(fā)出請(qǐng)求,建立連接后彈出對(duì)話框結(jié)束

2.使用ServerSocket建立聊天服務(wù)器

會(huì)阻塞主線程的程序應(yīng)該單獨(dú)放在一個(gè)線程中

創(chuàng)建ChatSocket類繼承自Thread烙无,用于執(zhí)行客戶端連接后的輸出操作

//聲明Socket對(duì)象

Socket

socket

;

//構(gòu)造函數(shù)接收外部傳入的SocketpublicChatSocket(Sockets

){

this.socket=s

;

}

創(chuàng)建輸出函數(shù)锋谐,使用輸出流進(jìn)行輸出

publicvoidout(Stringout) {

socket.getOutputStream().write(out.getBytes("UTF-8"));

復(fù)寫Thread類的run方法,執(zhí)行輸出操作截酷,每隔1秒輸出一次

publicvoidrun() {intcount

= 0;

//不斷執(zhí)行輸出操作while(true

){

out(

"loop"+count

);

count

++;

try

{

//每隔1秒輸出一次

sleep(1000);

}

catch(InterruptedExceptione

) {

//TODOAuto-generated catch blocke

.printStackTrace();

}

自定義ServerListener類繼承自Thread涮拗,用于執(zhí)行偵聽客戶端的請(qǐng)求,創(chuàng)建socket,為每個(gè)客戶端進(jìn)行輸出操作

創(chuàng)建ServerSocket,繼承自Thread類

publicclassServerListenerextendsThread {

復(fù)寫run方法三热,規(guī)定端口鼓择,創(chuàng)建ServerSocket對(duì)象

ServerSocketserverSocket=newServerSocket(12345);

不斷循環(huán),每當(dāng)客戶端發(fā)出請(qǐng)求就漾,serverSocket.accept()方法執(zhí)行一次呐能,創(chuàng)建一個(gè)新Socket對(duì)象,將創(chuàng)建的socket傳入抑堡,啟動(dòng)輸出線程

while(true){

Socketsocket=serverSocket.accept();

newChatSocket(socket).start();

}

Telnet是進(jìn)行遠(yuǎn)程登錄的標(biāo)準(zhǔn)協(xié)議和主要方式它為用戶提供了在本地計(jì)算機(jī)上完成遠(yuǎn)程主機(jī)工作的能力摆出。可以用telnet命令來測(cè)試端口號(hào)是否正常打開還是關(guān)閉狀態(tài)首妖。

測(cè)試命令:控制臺(tái)輸入 ?telnet localhost 12345

會(huì)在控制臺(tái)不斷輸出請(qǐng)求結(jié)果

添加一個(gè)客戶端發(fā)出消息偎漫,其他客戶端接收消息的功能

創(chuàng)建ChatManager類,用于管理每個(gè)客戶端對(duì)象創(chuàng)建的用于聊天的ChatSocket線程對(duì)象

由于每個(gè)聊天服務(wù)器只能擁有一個(gè)ChatManger類有缆,所以使用單例模式

創(chuàng)建private的構(gòu)造方法和private對(duì)象象踊,public static返回對(duì)象的方法

//私有化構(gòu)造方法private

ChatManager() {}

//為當(dāng)前的類創(chuàng)建唯一的實(shí)例privatestaticfinalChatManagercm=new

ChatManager();

//創(chuàng)建返回唯一實(shí)例的public static方法publicstatic

ChatManager getChatManager() {

returncm

;

}

創(chuàng)建Vector,范型為ChatSocket妒貌,用于管理客戶端的聊天線程

//創(chuàng)建Vector通危,管理每一個(gè)客戶端創(chuàng)建的ServerSocket線程對(duì)象

Vector

vector=newVector<>();

創(chuàng)建向Vector中添加元素的方法

//Vector的添加方法publicvoidadd(ChatSocketcs

) {

vector.add(cs);

創(chuàng)建發(fā)布消息的方法,參數(shù)為發(fā)布消息的chatSocket和發(fā)布的消息

遍歷Vector的中的所有元素灌曙,對(duì)不是發(fā)布消息的其他ChatSocket執(zhí)行out方法

在發(fā)布消息的ChatSocket內(nèi)部調(diào)用此方法

//其中任意一個(gè)線程可以調(diào)用publish方法向其他的客戶端發(fā)布信息publicvoidpublish(ChatSocketcs,Stringout

) {

//遍歷vector中的元素for(inti= 0;i

++){

//創(chuàng)建方法內(nèi)部的本地對(duì)象

ChatSocket

cSocket=vector.get(i

);

//判斷菊碟,不向自身發(fā)布消息if(!cSocket.equals(cs

)){

//調(diào)用輸出方法,輸出需要發(fā)送的信息cSocket.out(out

);

}

當(dāng)客戶端連接時(shí)在刺,創(chuàng)建socket,創(chuàng)建ChatSocket,將創(chuàng)建的ChatSocket添加到ChatManager中

Socketsocket=serverSocket.accept();

ChatSocketchatSocket=newChatSocket(socket);chatSocket.start();//當(dāng)ChatSocket線程創(chuàng)建時(shí)逆害,將它添加到ChatManager中

ChatManager.getChatManager().add(

chatSocket);

當(dāng)前客戶端獲取輸出流進(jìn)行輸出

//向客戶端發(fā)送數(shù)據(jù)

socket.getOutputStream().write(outline.getBytes("UTF-8"));

在ChatSocket中,socket獲取輸出流蚣驼,out方法將獲取的字符串輸出

//通過輸出流進(jìn)行輸出publicvoidout(Stringout

) {

String

outline=out+"\n"

;

try

{

//向客戶端發(fā)送數(shù)據(jù)socket.getOutputStream().write(outline.getBytes("UTF-8"));

在ChatSocket的run方法中魄幕,將本ChatSocket的數(shù)據(jù),通過socket獲取輸入流

讀取本socket發(fā)送的信息颖杏,調(diào)用ChatManager的publish方法發(fā)送給其他ChatSocket

@Overridepublicvoid

run() {

try

{

//通過socket獲取輸入流纯陨,讀取當(dāng)前socket將要發(fā)送的信息

BufferedReader

reader=new

BufferedReader(

newInputStreamReader(socket.getInputStream(),"UTF-8"

));

String

line

;

//將本ChatSocket發(fā)送的數(shù)據(jù),轉(zhuǎn)發(fā)給其他客戶端while((line=reader.readLine()) !=null

){

ChatManager.getChatManager().publish(

this,line

);

}

3.在Android中創(chuàng)建socket客戶端

socket的創(chuàng)建不能在主線程中留储,新建異步線程翼抠,復(fù)寫doInBackground方法,完成socket創(chuàng)建获讳,連接與數(shù)據(jù)讀取的操作阴颖。

//讀取聊天信息的異步線程AsyncTask read =newAsyncTask() {

@OverrideprotectedVoiddoInBackground(Void... params) {

try{

//socket不能在主線程中//新建socket,參數(shù)為ip與端口號(hào)socket=newSocket(ip,12346);//通過socket的輸入輸出流,創(chuàng)建BufferedWriter與BufferedReaderwriter=newBufferedWriter(newOutputStreamWriter(socket.getOutputStream()));reader=newBufferedReader(newInputStreamReader(socket.getInputStream()));//向外發(fā)布成功的狀態(tài)publishProgress("@success");}catch(IOException e) {

Toast.makeText(getApplicationContext(),"無法建立連接",Toast.LENGTH_SHORT).show();e.printStackTrace();}

try{

String line;//通過reader讀取數(shù)據(jù)并向外發(fā)布while((line =reader.readLine())!=null){

publishProgress(line);}

}catch(IOException e) {

e.printStackTrace();}

return null;

復(fù)寫onProgressUpdate()方法用于接收doInBackground方法向外發(fā)布的數(shù)據(jù),更新主線程的ui

@Overrideprotected voidonProgressUpdate(String... values) {

//接收判斷丐膝,如果是成功量愧,則彈出提示if(values[0].equals("@success")){

Toast.makeText(MainActivity.this,"連接成功",Toast.LENGTH_SHORT).show();}

//在主ui線程中钾菊,更新接收到的消息tvChat.append("某人說:"+values[0]+"\n");super.onProgressUpdate(values);}

};

調(diào)用異步線程執(zhí)行

//調(diào)用異步線程執(zhí)行read.execute();

創(chuàng)建send方法,通過writer向外輸出數(shù)據(jù)

public voidsend(){

try{

tvChat.append("我說:"+etSend.getText().toString()+"\n");//通過writer輸出信息writer.write(etSend.getText().toString()+"\n");writer.flush();//清空ediText的內(nèi)容etSend.setText("");}catch(IOException e) {

e.printStackTrace();}

button的事件監(jiān)聽器中調(diào)用相應(yīng)的方法偎肃,添加互聯(lián)網(wǎng)訪問權(quán)限

@Overridepublic voidonClick(View v) {

switch(v.getId()){

caseR.id.btnConnect:

connect();break;caseR.id.btnSend:

send();break;}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末煞烫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子累颂,更是在濱河造成了極大的恐慌红竭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喘落,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡最冰,警方通過查閱死者的電腦和手機(jī)瘦棋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暖哨,“玉大人赌朋,你說我怎么就攤上這事∑茫” “怎么了沛慢?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)达布。 經(jīng)常有香客問我团甲,道長(zhǎng),這世上最難降的妖魔是什么黍聂? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任躺苦,我火速辦了婚禮,結(jié)果婚禮上产还,老公的妹妹穿的比我還像新娘匹厘。我一直安慰自己,他們只是感情好脐区,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布愈诚。 她就那樣靜靜地躺著,像睡著了一般牛隅。 火紅的嫁衣襯著肌膚如雪炕柔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天倔叼,我揣著相機(jī)與錄音汗唱,去河邊找鬼。 笑死丈攒,一個(gè)胖子當(dāng)著我的面吹牛哩罪,可吹牛的內(nèi)容都是我干的授霸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼际插,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碘耳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起框弛,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤辛辨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瑟枫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斗搞,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年慷妙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了僻焚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膝擂,死狀恐怖虑啤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情架馋,我是刑警寧澤狞山,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站叉寂,受9級(jí)特大地震影響萍启,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屏鳍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一伊约、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧孕蝉,春花似錦屡律、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佳鳖,卻和暖如春霍殴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背系吩。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工来庭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人穿挨。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓月弛,卻偏偏與公主長(zhǎng)得像肴盏,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帽衙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容