Java網(wǎng)絡(luò)編程之簡(jiǎn)單的服務(wù)端客戶端應(yīng)用實(shí)例
本文實(shí)例講述了Java網(wǎng)絡(luò)編程之簡(jiǎn)單的服務(wù)端客戶端應(yīng)用。分享給大家供大家參考。具體如下:
在Java中,我們使用java.net.Socket及其相關(guān)類來(lái)完成有關(guān)網(wǎng)絡(luò)的相關(guān)功能。Socket類非常簡(jiǎn)單易用,因?yàn)镴ava技術(shù)隱藏了建立網(wǎng)絡(luò)連接和通過(guò)連接發(fā)送數(shù)據(jù)的復(fù)雜過(guò)程。下面所說(shuō)的內(nèi)容只適用于TCP協(xié)議。
一、連接到服務(wù)器
我們可以使用Socket類的構(gòu)造函數(shù)來(lái)打開(kāi)一個(gè)套接字,如
Socket sk = new Socket("210.0.235.14",13);
其中,210.0.235.14是一個(gè)點(diǎn)分十進(jìn)制的String對(duì)象,表示目的主機(jī)的IP地址(或主機(jī)名), 13表示指定連接目標(biāo)主機(jī)的13端口。這里的210.0.235.14是位于香港的一個(gè)授時(shí)服務(wù)器,授時(shí)服務(wù)器默認(rèn)的端口一般都為13.
注意,在成功連接到服務(wù)器之前,程序會(huì)阻塞。
接下來(lái)可以使用Socket類的getInputStream()方法來(lái)得到一個(gè)InputStream對(duì)象,通過(guò)這個(gè)對(duì)象就可以獲取到目標(biāo)主機(jī)給我們發(fā)過(guò)來(lái)的信息:
InputStream inStream = sk.getInputStream();
同理,要向目標(biāo)主機(jī)發(fā)送數(shù)據(jù),則可以調(diào)用getOutputStream()方法來(lái)獲取一個(gè)輸出流對(duì)象。
下面的例子功能是連接授時(shí)服務(wù)器,并將返回的信息打印到標(biāo)準(zhǔn)輸出中:
try
{
Socket sk = new Socket("210.0.235.14",13);
sk.setSoTimeout(3000);
InputStream inStream = sk.getInputStream();
//得到輸入流對(duì)象
Scanner sc = new Scanner(inStream);
//將數(shù)據(jù)打印到控制臺(tái)
while(sc.hasNextLine())
{
String str = sc.nextLine();
System.out.println("Output : " + str);
}
sk.close();
}
catch(SocketTimeoutException e) //超時(shí)異常
{
System.out.println("Time Out!");
}
catch(Exception e)
{
e.printStackTrace();
}
代碼中setSoTimeout()方法可以設(shè)置超時(shí)時(shí)間,即如果超過(guò)了設(shè)定時(shí)間還沒(méi)有完成讀寫(xiě)操作,則會(huì)拋出SocketTimeoutException,可以通過(guò)捕獲這個(gè)異常來(lái)關(guān)閉連接。
另外還有一個(gè)超時(shí)問(wèn)題是必須要解決的,就是這個(gè)Socket類的構(gòu)造函數(shù)
new Socket(host,port);
會(huì)一直無(wú)限地阻塞下去,直到成功建立了到目標(biāo)主機(jī)的連接為止。這當(dāng)然不是我們所希望的。我們可以通過(guò)如下調(diào)用方式解決此問(wèn)題:
Socket sk = new Socker(); sk.connect(new InetSocketAddress(host,port),2000); //設(shè)置超時(shí)時(shí)間為2秒
二、獲取主機(jī)地址
InetAddress類的靜態(tài)方法getByName(hostname)可以返回代表了某個(gè)主機(jī)地址的InetAddress對(duì)象,這個(gè)對(duì)象封閉了一個(gè)4字節(jié)的序列,即主機(jī)的IP地址。然后再調(diào)用getHostAddress()方法返回一個(gè)表示IP地址的String對(duì)象.
一些訪問(wèn)量大的主機(jī)名通常會(huì)對(duì)應(yīng)著多個(gè)IP地址以實(shí)現(xiàn)負(fù)載均衡。我們可以調(diào)用getAllByName()方法來(lái)獲得所有主機(jī)地址,該方法返回一個(gè)InetAddress對(duì)象的數(shù)組。
下面是一個(gè)簡(jiǎn)單的小程序,實(shí)現(xiàn)的功能是,如果不在命令行中設(shè)置參數(shù),就打印出本地的IP地址,如果指定了主機(jī)名,則打印出該主機(jī)所有的IP地址:
package cls;
import java.net.*;
public class ShowIP
{
public static void main(String[] args)
{
try
{
if(args.length > 0)
{
String hostName = args[0]; //主機(jī)名
InetAddress[] addr = InetAddress.getAllByName(hostName);
//得到該主機(jī)的所有地址
//打印輸出至控制臺(tái)
for(InetAddress address : addr)
{
System.out.println(address.getHostAddress());
}
}
else
{
System.out.println(InetAddress.getLocalHost().getHostAddress());
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
三、服務(wù)器端程序
服務(wù)器端應(yīng)用程序使用ServerSocket類來(lái)創(chuàng)建套接字,并鈄其綁定至本地端口中,如
ServerSocket sock = new ServerSocker(8000);
sock.accept()方法讓程序不停地等待連接,該方法只有當(dāng)有客戶端連接時(shí)才會(huì)返回一個(gè)代表了新連接的Socket對(duì)象,即該方法會(huì)發(fā)生阻塞。
這里一般要為每個(gè)連接新開(kāi)啟一個(gè)線程為其服務(wù)。
下面是一個(gè)完整的例子,服務(wù)端在8400端口處等待連接,每當(dāng)連接到來(lái)時(shí),新開(kāi)一個(gè)線程為其服務(wù),并將連接信息寫(xiě)入的日志文件中:
package cls;
import java.io.*;
import java.net.*;
import java.util.*;
public class ServerDemo
{
/**
* @param args
*/
public static void main(String[] args)
{
try
{
//ServerSocket servSocket = new ServerSocket(8000);
ServerSocket servSocket = new ServerSocket(8400);
int amount = 0;
while(true)
{
Socket client = servSocket.accept();
++amount;
Date time = new Date();
String prompt = time.toString() + ": 第" + amount + "個(gè)用戶 " + client.getInetAddress().getHostAddress() + " 已連接\n";
System.out.print(prompt); //在控制臺(tái)輸出信息
ServerDemo.writeLog(prompt); //寫(xiě)入到文件中
//start a new Thread
Thread th = new Thread(new ServThread(client,amount));
th.start();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
//寫(xiě)入日志文件
public static void writeLog(String str)
{
File logFile = new File("server-log.txt");
try
{
FileWriter out = new FileWriter(logFile,true);
out.append(str);
out.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
/*
* 服務(wù)線程類
*/
class ServThread implements Runnable
{
private Socket client;
private int ix;
public ServThread(Socket soc,int ix)
{
client = soc;
this.ix = ix;
}
public void run()
{
try
{
InputStream inStream = client.getInputStream();
OutputStream outStream = client.getOutputStream();
Scanner recv = new Scanner(inStream);
PrintWriter send = new PrintWriter(outStream,true);
send.println("歡迎~隨便聊幾句吧![輸入'bye'關(guān)閉聯(lián)接]");
while(recv.hasNextLine())
{
String str = recv.nextLine();
if(str.equals("bye"))
{
send.println("See you later ~ ^-^");
break;
}
send.println("這是個(gè)測(cè)試程序,現(xiàn)在還沒(méi)有什么功能哦");
}
Date time = new Date();
String prompt = time.toString() + ": 第" + ix + "個(gè)用戶 " + client.getInetAddress().getHostAddress() + " 已斷開(kāi)連接\n";
System.out.print(prompt);
ServerDemo.writeLog(prompt); //寫(xiě)入到文件中
client.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
這個(gè)程序已經(jīng)被放到了服務(wù)器上,大家可以使用telnet youthol.tk 8400 命令來(lái)體驗(yàn)一下這個(gè)程序的運(yùn)行結(jié)果
希望本文所述對(duì)大家的java程序設(shè)計(jì)有所幫助。
- Java網(wǎng)絡(luò)編程基礎(chǔ)篇之單向通信
- Java 網(wǎng)絡(luò)編程socket編程等詳解
- 簡(jiǎn)單講解Java的Socket網(wǎng)絡(luò)編程的多播與廣播實(shí)現(xiàn)
- Java的Socket網(wǎng)絡(luò)編程基礎(chǔ)知識(shí)入門(mén)教程
- Java套接字(Socket)網(wǎng)絡(luò)編程入門(mén)
- 簡(jiǎn)單介紹Java網(wǎng)絡(luò)編程中的HTTP請(qǐng)求
- Java網(wǎng)絡(luò)編程基礎(chǔ)教程之Socket入門(mén)實(shí)例
- java網(wǎng)絡(luò)編程基礎(chǔ)知識(shí)介紹
相關(guān)文章
Mybatis-Plus中Mapper的接口文件與xml文件相關(guān)的坑記錄
這篇文章主要介紹了Mybatis-Plus中Mapper的接口文件與xml文件相關(guān)的坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
java對(duì)象強(qiáng)轉(zhuǎn)成object的方法實(shí)現(xiàn)
在 Java 編程中,有時(shí)候我們需要將一個(gè)具體的對(duì)象強(qiáng)制轉(zhuǎn)換成 Object 類型,本文主要介紹了java對(duì)象強(qiáng)轉(zhuǎn)成object的方法實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
Java 9中如何對(duì)IntegerCache進(jìn)行修改詳解
這篇文章主要給大家介紹了關(guān)于Java 9中如何對(duì)IntegerCache進(jìn)行修改的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或使用java9具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起看看吧。2017-12-12
Java分頁(yè)查詢的幾種實(shí)現(xiàn)方法舉例
這篇文章主要給大家介紹了關(guān)于Java分頁(yè)查詢的幾種實(shí)現(xiàn)方法,分頁(yè)是系統(tǒng)中常用到的功能,只要涉及到查詢必定伴隨而來(lái)的就是分頁(yè),文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
java實(shí)現(xiàn)網(wǎng)頁(yè)爬蟲(chóng)的示例講解
下面小編就為大家?guī)?lái)一篇java實(shí)現(xiàn)網(wǎng)頁(yè)爬蟲(chóng)的示例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
java之Timer和TimerTask簡(jiǎn)單demo(分享)
下面小編就為大家?guī)?lái)一篇java之Timer和TimerTask簡(jiǎn)單demo(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)隊(duì)列簡(jiǎn)單定義與用法示例
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)隊(duì)列簡(jiǎn)單定義與用法,簡(jiǎn)要描述了循環(huán)隊(duì)列的概念、原理,并結(jié)合實(shí)例形式分析了java循環(huán)隊(duì)列的定義與使用方法,需要的朋友可以參考下2017-10-10
springboot中Controller內(nèi)文件上傳到本地及阿里云操作方法
這篇文章主要介紹了springboot中Controller內(nèi)文件上傳到本地及阿里云操作方法,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-12-12

