Java网络编程
---------- android培训、java培训、期待与您交流!----------
1、网络编程
Java中提供了专门用于开发网络程序所需要的包——java.net,方便开发者使用其进行网络应用开发,网络编程提供了两种通信协议:TCP与UDP。UDP:为User Datagram Protocol的简写,是面向无连接的,将数据及源封装在数据包中,不需要事先建立连接,每个数据报的大小为64kb, 为不可靠的传输,但是速度快。
TCP:为Transmission Control Protocol的简写, 事先需要通过三次握手建立连接,形成传输通道,为可靠的传输,但是速度慢。
2、UDP程序设计
UDP协议使用DatagramSocket与DatagramPacket作为Socket,用于发送和接收数据包。在UDP开发中,使用DatagramPacket类包装一条要发送的信息,之后使用DatagramSocket类用于完成信息的发送操作。(1) DatagramPacket:
构造方法:
DatagramPacket(byte[] buf, int length)
构造 DatagramPacket,用来接收长度为length的数据包
DatagramPacket(byte[] buf, int offset, int length)
构造 DatagramPacket,用来接收长度为length的包,在缓冲区中指定了偏移量
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为length的包发送到指定主机上的指定端口号
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
构造数据报包,用来将长度为length偏移量为offset的包发送到指定主机上的指定端口号
(2) DatagramSocket:
构造方法:
DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口
DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口
DatagramSocket(int port, InetAddress laddr):创建数据报套接字,将其绑定到指定的本地地址
常用方法:
void receive(DatagramPacket p):从此套接字接收数据报包
void send(DatagramPacket p):从此套接字发送数据报包
void close():关闭此数据报套接字
InetAddress getInetAddress():返回此套接字连接的地址
InetAddress getLocalAddress():获取套接字绑定的本地地址
int getLocalPort():返回此套接字绑定的本地主机上的端口号
int getPort():返回此套接字的端口
从上面的receive和send方法可以看出,使用DatagramSocket发送数据报时,DatagramSocket并不知道将该数据报发送到哪,而是由DatagramPacket自身决定数据报的目的,DatagramPacket包含了发送目的地。
下面的示例代码演示了发送端循环从键盘录入信息并向接收端发送数据:
发送端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Send {
public static void main(String[] args) {
DatagramSocket ds = null;
try {
ds = new DatagramSocket(8888);
BufferedReader bufr = new BufferedReader(
new InputStreamReader(System.in));
String line = null;
try {
while((line=bufr.readLine()) != null){
if("exit".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getByName("192.168.17.22"),10000);
ds.send(dp);
}
} catch (IOException e) {
e.printStackTrace();
}
ds.close();
} catch (SocketException e) {
e.printStackTrace();
}
}
}
接收端:
class Receive{
public static void main(String[] args){
DatagramSocket ds = null;
try {
ds = new DatagramSocket(10000);
while(true){
byte[] buf = new byte[1024*64];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
try {
ds.receive(dp);
} catch (IOException e) {
e.printStackTrace();
}
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+": "+port+": "+data);
}
} catch (SocketException e) {
e.printStackTrace();
}
}
}
下面的代码结合了多线程技术实现了同时发送与接收数据:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class ChatDemo3 {
public static void main(String[] args) throws SocketException{
DatagramSocket send = new DatagramSocket();
DatagramSocket get = new DatagramSocket(10001);//指定要监听的端口
new Thread(new SendMe(send)).start();
new Thread(new GetMe(get)).start();;
}
}
class SendMe implements Runnable{
private DatagramSocket s;
public SendMe(DatagramSocket ss){
this.s = ss;
}
public void run() {
while(true){
String data = null;
BufferedReader d = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println("输入内容:");
data = d.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if("exit".equals(data))
break;
byte[] dat = data.getBytes();
DatagramPacket p = null;
try {
p = new DatagramPacket(dat, dat.length,InetAddress.getByName("192.168.17.22"), 10000);
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
try {
s.send(p);
} catch (IOException e) {
e.printStackTrace();
}
}
s.close();
}
}
class GetMe implements Runnable{
private DatagramSocket s;
public GetMe(DatagramSocket ss){
this.s = ss;
}
public void run(){
while(true){
byte[] buf = new byte[1024];
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
s.receive(p);
} catch (IOException e) {
e.printStackTrace();
}
String ip = p.getAddress().getHostAddress();
int port = p.getPort();
String data = new String(p.getData(), 0, p.getLength());
System.out.println(ip+port+data);
}
}
}
3、TCP程序设计
TCP网络通信分为两个端点,即客户端和服务器端,由于TCP协议是面向连接的协议,必须要有一个通信实体主动接收来自其它通信实体的连接请求。
(1) ServerSocket:Java中能接收其它通信实体连接请求的类是ServerSocket,ServerSocket对象作为服务端用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待状态
构造方法:
ServerSocket():创建非绑定服务器套接字
ServerSocket(int port):创建绑定到特定端口的服务器套接字
ServerSocket(int port, int backlog):利用指定的backlog 创建服务器套接字并将其绑定到指定的本地端口号
ServerSocket(int port, int backlog, InetAddress bindAdr):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器
常用方法:
Socket accept():侦听并接受到此套接字的连接
void close():关闭此套接字
InetAddress getInetAddress():返回此服务器套接字的本地地址
int getLocalPort():返回此套接字在其上侦听的端口
SocketAddress getLocalSocketAddress():返回此套接字绑定的端点的地址,如果尚未绑定则返回null
boolean isBound():返回 ServerSocket 的绑定状态
boolean isClosed():返回 ServerSocket 的关闭状态
构造方法:
Socket(InetAddress address, int port):创建一个流套接字并将其连接到指定IP地址的指定端口号
Socket(String host, int port):创建一个流套接字并将其连接到指定主机上的指定端口号
Socket(InetAddress address, int port, InetAddress localAddr, int localPort):创建一个套接字并将其连接到指定远程地址上的指定远程端口
Socket(String host, int port, InetAddress localAddr, int localPort):创建一个套接字并将其连接到指定远程主机上的指定远程端口
常用方法:
void close():关闭此套接字
InetAddress getInetAddress():返回套接字连接的地址
InetAddress getLocalAddress():获取套接字绑定的本地地址
int getPort():返回此套接字连接到的远程端口
int getLocalPort():返回此套接字绑定到的本地端口
InputStream getInputStream():返回此套接字的输入流
OutputStream getOutputStream():返回此套接字的输出流
boolean isBound():返回套接字的绑定状态
boolean isClosed():返回套接字的关闭状态
void shutdownInput():此套接字的输入流置于“流的末尾”
void shutdownOutput():禁用此套接字的输出流
void setSoTimeout(int timeout):启用/禁用带有指定超时值的SO_TIMEOUT,以毫秒为单位
(a) 下面的实例程序演示了使用TCP协议的通信程序:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
public static void main(String[] args) {
try {
Socket s = new Socket("192.168.17.22",20001);
OutputStream out = s.getOutputStream();
out.write("Hello".getBytes());
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
in.read(buf);
System.out.println(new String(buf,0,buf.length));
in.close();
out.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class TCPServer{
public static void main(String[] args){
try {
ServerSocket ss = new ServerSocket(20001);
Socket s = ss.accept();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf, 0, buf.length);
System.out.println(new String(buf,0,len));
OutputStream out = s.getOutputStream();
out.write("Copy That".getBytes());
out.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(b) 下面的程序演示了使用TCP在网络上复制文件:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPFileCopy {
public static void main(String[] args) {
try {
Socket s = new Socket("192.168.56.29",10009);
File file = new File("demo.jpg");
FileInputStream filein = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=filein.read(buf)) != -1){
out.write(buf, 0, len);
}
s.shutdownOutput();//需要告知服务端,上传结束
InputStream in = s.getInputStream();
buf = new byte[1024];
len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
filein.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Copy {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10009);
Socket s = ss.accept();
InputStream in = s.getInputStream();
FileOutputStream fileout = new FileOutputStream("copy.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf)) != -1){
fileout.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
out.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedWriter可以使用PrintWriter代替,可以省去newLine,flush方法,可以自动刷新。
(c) 下面的程序演示了使用多线程技术实现多用户连接服务端:
package com.example.tcp;
import java.io.*;
import java.net.*;
public class FileCopyMultipleServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10081);
while(true){
Socket s = ss.accept();//等待客户端连接
new Thread(new PicThread(s)).start();//客户端连接后,线程开启执行,循环继续等待客户端连接
}
}
}
class PicThread implements Runnable{
private Socket s;
PicThread(Socket s){
this.s = s;
}
public void run(){
try {
InputStream i = s.getInputStream();
System.out.println(s.getInetAddress().getHostAddress()+"...is connected...");
BufferedReader readname = new BufferedReader(new InputStreamReader(i));
String name = readname.readLine();
System.out.println("文件名为:"+name);
//判断文件是否存在
File f = new File(name);
int pos = name.lastIndexOf(".");
int count = 1;
while(f.exists())
f = new File(name.substring(0, pos)+"("+(count++)+")"+name.substring(pos,name.length()));
System.out.println("复制的文件为:"+f);
FileOutputStream fileout = new FileOutputStream(f);
//传输文件
InputStream in = s.getInputStream();
int len = 0;
byte[] buf = new byte[1024];
while((len=in.read(buf)) != -1){
fileout.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fileout.close();
out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class UploaderClient {
public static void main(String[] args) throws IOException {
copy();
}
public static void run() throws IOException{
Socket s = new Socket("192.168.56.29",10081);
File file = new File("demo.jpg");
FileInputStream filein = new FileInputStream(file);
//将文件名发送至服务端
System.out.println("文件为:"+file.getName());
System.out.println("正在上传...");
PrintWriter writename = new PrintWriter(s.getOutputStream());
writename.write(file.getName()+'\n');
writename.flush();
//将文件数据发送至服务端
OutputStream out = s.getOutputStream();
int len = 0;
byte[] buf = new byte[1024];
while((len=filein.read(buf)) != -1){
out.write(buf,0,len);
}
s.shutdownOutput();
InputStream in = s.getInputStream();
buf = new byte[1024];
len = in.read(buf);
System.out.println(new String(buf,0,len));
filein.close();
out.close();
in.close();
s.close();
}
public static void copy(){
long t1 = System.currentTimeMillis();
try {
run();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("耗时:"+(float)(System.currentTimeMillis()-t1)/1000+"秒");
}
}
以上代码实现了客户端向服务端上传文件,并计算了上传时间。
---------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------