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

