是回路地址用于测试相当于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工具来查看已经被使用的端口