是回路地址用於測試相當於localhost本機地址沒有網卡不設DNS都可以訪問
端口地址在~之間其中~之間的端口是用於一些知名的網絡服務和應用用戶的普通網絡應用程序應該使用以上的端口
網絡應用中基本上都是TCP(Transmission Control Protocol傳輸控制協議)和UDP(User Datagram Protocol用戶數據報協議)TCP是面向連接的通信協議UDP是無連接的通信協議
Socket連接套接字Java分別為TCP和UDP提供了相應的類TCP是ServerSocket(用於服務器端)和Socket(用於客戶端);UDP是DatagramSocket
Java編寫UDP網絡程序
DatagramSocket
DatagramSocket有如下構造方法:
DatagramSocket() :構造數據報套接字並將其綁定到本地主機上任何可用的端口
DatagramSocket(int port):創建數據報套接字並將其綁定到本地主機上的指定端口
DatagramSocket(int port InetAddress laddr):創建數據報套接字將其綁定到指定的本地地址即指定網卡發送和接收數據
如果在創建DatagramSocket對象時沒有指定網卡的IP 地址在發送數據時底層驅動程序會自動選擇一塊網卡去發送在接收數據時會接收所有的網卡收到的與端口一致的數據
發送信息時可以不指定端口號接收信息時要指定端口號因為要接收指定的數據
發送數據使用DatagramSocketsend(DatagramPacket p)方法接收數據使用DatagramSocketreceive(DatagramPacket p)方法
DatagramPacket
DatagramPacket類有如下構造方法:
DatagramPacket(byte[] buf int length):構造 DatagramPacket用來接收長度為length的數據包
DatagramPacket(byte[] buf int length InetAddress address int port):構造數據報包用來將長度為length的包發送到指定主機上的指定端口號
接收數據時使用第一次構造方法發送數據時使用第二種構造方法
InetAddress
Java中對IP地址進行包裝的類
DatagramPacketgetAddress()可以獲取發送或接收方的IP地址DatagramPacketgetPort()可以獲取發送或接收方的端口
UDP程序例子
發送程序:
import DatagramPacket;
import DatagramSocket;
import InetAddress;
public class UdpSend {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
String str = hello world!;
DatagramPacket dp = new DatagramPacket(strgetBytes()strlength()InetAddressgetByName());
dssend(dp);
dsclose(); //關閉連接
}
}
接收程序:
import DatagramPacket;
import DatagramSocket;
public class UdpRecv {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
byte[] buf = new byte[];
DatagramPacket dp = new DatagramPacket(bufbuflength);
dsreceive(dp);
String str = new String(dpgetData()dpgetLength());
Systemoutprintln(str);
Systemoutprintln(IP: + dpgetAddress()getHostAddress() + PORT: + dpgetPort());
dsclose();
}
}
測試要先運行接收程序再運行發送程序如果接收程序沒有接收到數據則會一直阻塞接收到數據後才會關閉程序如果網絡上沒有數據發送過來接收程序也沒有阻塞通常都是使用了一個已經被占用的端口
Java編寫TCP網絡程序
ServerSocket
編寫TCP網絡服務程序首先要用到ServerSocket類用以創建服務器Socket它的常用構造方法有:
ServerSocket(int port):創建綁定到特定端口的服務器套接字
ServerSocket(int port int backlog):利用指定的backlog(服務器忙時保持連接請求的等待客戶數量)創建服務器套接字並將其綁定到指定的本地端口號
ServerSocket(int port int backlog InetAddress bindAddr):使用指定的端口偵聽 backlog 和要綁定到的本地 IP 地址創建服務器
Socket
客戶端要與服務器建立連接必須先創建一個Socket對象它的常用構造方法有:
Socket(String host int port):創建一個流套接字並將其連接到指定主機上的指定端口號
Socket(InetAddress address int port):創建一個流套接字並將其連接到指定 IP 地址的指定端口號
Socket(InetAddress address int port InetAddress localAddr int localPort):創建一個套接字並將其連接到指定遠程端口上的指定遠程地址
Socket(String host int port InetAddress localAddr int localPort):創建一個套接字並將其連接到指定遠程主機上的指定遠程端口
對於通常情況的應用使用第個構造方法來創建客戶端的Socket對象並與服務器建立連接是非常簡單和方便的
服務器端程序調用ServerSocketaccept方法等待客戶端的連接請求一旦accept接收了客戶端連接請求該方法返回一個與該客戶端建立了專線連接的Socket對象不用程序去創建這個Socket對象建立了連接的兩個Socket是以IO流的方式進行數據交換的Java提供了SocketgetInputStream返回Socket的輸入流對象SocketgetOutputStream返回Socket的輸出流對象
TCP程序例子的服務器程序:
import javaioInputStream;
import javaioOutputStream;
import ServerSocket;
import Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket();
Socket s = ssaccept();
InputStream ips = sgetInputStream();
OutputStream ops = sgetOutputStream();
opswrite(helloWorld!getBytes());
byte[] buf = new byte[];
int len = ipsread(buf);
Systemoutprintln(new String(buflen));
ipsclose();
opsclose();
sclose();
ssclose();
}
}
在這個程序裡創建了一個在端口上等待連接的ServerSocket對象當接收到一個客戶的連接請求後程序從與這個客戶建立了連接的Socket對象中獲得輸入輸出流對象通過輸出流首先向客戶端發送一串字符然後通過輸入流讀取客戶端發送過來的信息並將這些信息打印然後關閉所有資源
要先運行服務器程序然後才能運行客戶端程序當TCP服務器程序運行到Socketaccpet()方法等待客戶連接時accept方法將阻塞一直到有客戶連接請求到來該方法才會返回如果又沒有請求到來又沒有發生阻塞通常都是使用了一個已經被占用的端口
我們可以使用windows提供的telnet工具在命令行窗口中測試一下服務器程序:命令如下:telnet localhost
可以看到telnet只要有輸入就發送因此我們如果想要在服務器端一次讀多個字符的話還需要進一步處理看如下代碼:
import javaioBufferedReader;
import javaioInputStream;
import javaioInputStreamReader;
import javaioOutputStream;
import ServerSocket;
import Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket();
Socket s = ssaccept();
InputStream ips = sgetInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(ips)); //對InputStream進行包裝增加了緩存
OutputStream ops = sgetOutputStream();
opswrite(helloWorld!getBytes());
Systemoutprintln(brreadLine());
brclose(); //關閉包裝類會自動關閉裡面的基類
opsclose();
sclose();
ssclose();
}
}
再次使用telnet工具可以看到這次可以發送不止一個字符了按回車鍵後發送數據到服務器端
TCP程序例子改進後的服務器程序:
大多數情況下服務器端都要服務多個客戶端但一次accept方法調用只接收一個連接因此要把accept方法放在一個循環語句中這樣就可以接收多個連接每個連接的數據交換代碼也放在一個循環中這樣才能保證兩者可以不停地交換數據
每個連接的數據交換代碼必須放在獨立的線程中運行否則這在段代碼運行期間就沒法執行其他的程序代碼accept方法也得不到調用新的連接無法進入
下面是一個例子客戶端向服務器發送一個字符串服務器將這個字符串中的所有字符反向排列後回送給客戶端客戶端輸入quit退出程序
import javaioBufferedReader;
import javaioDataOutputStream;
import javaioInputStream;
import javaioInputStreamReader;
import javaioOutputStream;
import ServerSocket;
import Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket();
while(true){
Socket s = ssaccept();
new Thread(new Servicer(s))start();
}
}
}
class Servicer implements Runnable{
Socket s;
public Servicer(Socket s){
thiss = s;
}
public void run(){
try{
InputStream ips = sgetInputStream();
OutputStream ops = sgetOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(ips));
DataOutputStream dos = new DataOutputStream(ops);
while(true){
String strWord = brreadLine();
if(strWordequalsIgnoreCase(quit)){
break;
}
String strEcho = (new StringBuffer(strWord)reverse()toString());
doswriteBytes(strWord + > + strEcho + SystemgetProperty(lineseparator));
}
brclose();
dosclose();
sclose();
}catch(Exception e){
eprintStackTrace();
}
}
}
TCP程序例子客戶端程序:
import javaioBufferedReader;
import javaioDataOutputStream;
import javaioInputStream;
import javaioInputStreamReader;
import javaioOutputStream;
import InetAddress;
import Socket;
public class TcpClient {
public static void main(String[] args) throws Exception{
if(argslength < ){
Systemoutprintln(Usage:java TcpClient ServerIP ServerPort);
return ;
}
Socket s = new Socket(InetAddressgetByName(args[])IntegerparseInt(args[]));
InputStream ips = sgetInputStream();
OutputStream ops = sgetOutputStream();
BufferedReader brKey = new BufferedReader(new InputStreamReader(Systemin));
DataOutputStream dos = new DataOutputStream(ops);
BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
while(true){
String strWord = brKeyreadLine();
doswriteBytes(strWord + SystemgetProperty(lineseparator));
if(quitequalsIgnoreCase(strWord)){
break;
}else{
Systemoutprintln(brNetreadLine());
}
}
dosclose();
brNetclose();
brKeyclose();
sclose();
}
}
先運行服務器程序再在命令行使用java TcpClient 這樣就啟動了客戶端程序我們可以啟動多個客戶端程序
我們可以利用netstat工具來查看已經被使用的端口
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26522.html