您的位置:首页 > 理论基础 > 计算机网络

Java语言基础-网络编程

2012-08-18 12:53 519 查看
网络模型

OSI(Open System Interconnection 开放系统互连)参考模型
——(底层到上层)物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
TCP(传输控制协议):传输效率低,可靠性强。用于传输的可靠性要求高,数据量大的数据。
UDP(用户数据报协议):与TCP特性相反,用于传输可靠性要求不高,数据量小的数据。
TCP/IP参考模型
——主机至网络,网络层,传输层,应用层

网络通讯要素
IP地址(InteAddress)
网络中设备的标识
不易记忆,可用主机名
本机回环地址:127.0.0.1 主机名:localhost
端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0~65535,其中0~1024系统是使用或保留端口
传输协议
通讯的协议
常见协议:TCP、UDP
UDP
将数据及源和目的封装到数据包中,不需要建立连接;
每个数据包的大小限制在64K以内;
因无连接,是不可靠协议;
不需要建立连接,速度快。
TCP
建立连接,形成传输数据的通道;
在连接中进行大量数据传输;
通过三次握手完成连接,是可靠协议;
必须建立连接,效率稍低。

public class InetAddress
extends Object
implements Serializable
此类表示互联网协议 (IP) 地址。

static InetAddress getLocalHost() ;//返回本地主机。

InetAddress方法示例:

package cn.itcast.net.p1.ip;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IPDemo {

/**
* @param args
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException {

// 获取本地主机IP地址对象
InetAddress ip = InetAddress.getLocalHost();

// 获取其他主机的IP地址对象
// ip=InetAddress.getByName("192.168.0.101");
ip = InetAddress.getByName("www.baidu.com");

System.out.println(ip.getHostAddress());
System.out.println(ip.getHostName());
}

}


Socket
Socket就是为网络服务提供的一种机制;
通信的两端都有Socket;
网络通信其实就是Socket间的通信;
数据在两个Socket间通过IO传输。

UDP传输
DatagramSocket和DatagramPacket

UDP传输示例:

package cn.itcast.net.p2.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPSendDemo {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

System.out.println("发送端启动......");
/*
* 创建UDP传输的发送端
* 思路:
* 1.建立UDP的Socket服务;
* 2.将要发送的数据封装到数据包中;
* 3.通过UDP的Socket服务,将数据包发送出去;
* 4.关闭Socket服务。
*/
// 1.UDP的Scoket服务,使用DatagramSocket对象.
DatagramSocket ds = new DatagramSocket(8888);

// 2.将要发送的数据封装到数据包中。
String str = "UDP传输演示...";
// 使用DatagramPacket将对象封装到包中
byte[] buf = str.getBytes();

DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getByName("192.168.0.101"), 10000);

//3.通过UDP的Socket服务将数据包发送出去。使用send方法
ds.send(dp);

//4.关闭资源
ds.close();

}

}


package cn.itcast.net.p2.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceiveDemo {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

System.out.println("接收端启动......");
/*
* 建立UDP接收端的思路:
* 1.建立UDP的Socket服务;因为要接收数据,必须明确端口号;
* 2.创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析数据;
* 3.使用Socket服务的receive方法将接收到的方法存储到数据包中;
* 4.通过数据包的方法解析数据包中的数据;
* 5.关闭资源。
*/
//1.建立UDP的Socket服务
DatagramSocket ds=new DatagramSocket(10000);

//2.创建数据包
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf, buf.length);

//3.使用接收方法见数据存储到数据包中
ds.receive(dp);//阻塞式

//4.通过数据包对象的方法,解析其中的数据:地址、端口、数据内容等;
String ip=dp.getAddress().getHostAddress();
int port=dp.getPort();
String text=new String (dp.getData(),0,dp.getLength());

System.out.println(ip+":"+port+":"+text);
ds.close();
}

}


基于多线程的聊天程序:

package cn.itcast.net.p3.chat;

import java.io.IOException;
import java.net.DatagramSocket;

public class ChatDemo {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

DatagramSocket send=new DatagramSocket();

DatagramSocket rece=new DatagramSocket(10001);
new Thread(new Send(send)).start();
new Thread(new Rece(rece)).start();
}

}

package cn.itcast.net.p3.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
* 发送端
* @author chenchong
*
*/
public class Send implements Runnable {

private DatagramSocket ds;

public Send(DatagramSocket ds) {
this.ds = ds;
}

@Override
public void run() {

try {
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
String line = null;

while ((line = bufr.readLine()) != null) {
byte[] buf = line.getBytes();

DatagramPacket dp = new DatagramPacket(buf, buf.length,
InetAddress.getByName("192.168.0.255"), 10001);//IP地址末尾为255,则发送广播
ds.send(dp);
if ("886".equals(line))
break;
}
ds.close();
} catch (Exception e) {
}
}

}

package cn.itcast.net.p3.chat;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
* 接收端
* @author chenchong
*
*/
public class Rece implements Runnable {

private DatagramSocket ds;

public Rece(DatagramSocket ds) {
this.ds = ds;
}

@Override
public void run() {
try {
while (true) {

byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);

ds.receive(dp);// 阻塞式

String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(), 0, dp.getLength());

System.out.println(ip + ":" + port + ":" + text);

if (text.equals("886")) {
System.out.println(ip + ".....退出聊天室");
}
// ds.close();//此处如果关闭资源,则只接收一次
}
} catch (Exception e) {
}
ds.close();
}

}


TCP传输
建立客户端和服务器端;
建立连接后,通过Socket中的IO流进行数据的传输;
关闭Socket。
客户端与服务器端是两个独立的应用程序。

public class Socket extends Object
此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
public class ServerSocket extends Object
此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果

TCP示例:

package cn.itcast.net.p4.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

/*
*服务端接收客户端发送过来的数据,并打印在控制台上
*
* 建立TCP服务端:
* 1.创建服务端Socket服务,通过ServerSocket对象;
* 2.服务端必须对外提供一个端口,否则客户端无法连接;
* 3.获取连接过来的客户端对象;
* 4.通过客户端对象获取Socket流读取客户端发送的数据,
*     并打印在控制台上;
* 5.关闭资源:关客户端;关服务端。
*/

//1.创建服务端对象
ServerSocket ss=new ServerSocket(10002);

//2.获取连接过来的服务端对象
Socket s=ss.accept();

//3.通过Socket对象获取输入流,读取客户端发来的数据
InputStream in=s.getInputStream();

String ip=s.getInetAddress().getHostAddress();

//4.获取客户端发来的数据
byte[] buf=new byte[1024];

int len=in.read(buf);
String text=new String(buf,0,len);
System.out.println(ip+":"+text);

//5.关闭资源
s.close();
ss.close();

}

}


package cn.itcast.net.p4.tcp;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientDemo {

/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException,
IOException {
/*
* 需求:客户端发送数据到服务端
*
* TCP传输,客户端的建立
* 1.创建TCP客户端Socket服务,使用的是Socket对象,
* 建议该对象一创建就明确目的地(要连接的主机);
* 2.如果连接建立成功,说明数据传输通道已建立;
* 通道就是Socket流,是底层建立的,这里既有输入又有输出。
* 想要输入或者输出流对象,可以找Socket流获取;
* 可以通过getOutputStream()和getInputStream()来获取两个字节流;
* 3.使用输出流,将数据写出;
* 4.关闭资源。
*/

// 创建客户端Socket服务
Socket socket = new Socket("192.168.0.101", 10002);

// 获取Socket流中的输出流
OutputStream out = socket.getOutputStream();

// 使用输出流将指定的数据写出去
out.write("TCP演示:这里是客户端......".getBytes());

// 关闭资源(将连接断开)
socket.close();
}

}


服务端、客户端交互

package cn.itcast.net.p4.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo2 {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(10002);

Socket s=ss.accept();//阻塞式

InputStream in=s.getInputStream();

String ip=s.getInetAddress().getHostAddress();

byte[] buf=new byte[1024];

int len=in.read(buf);
String text=new String(buf,0,len);
System.out.println(ip+":"+text);

//使用客户端Socke对象的输出流给客户端返回数据
OutputStream out=s.getOutputStream();
out.write("server收到".getBytes());

//5.关闭资源
s.close();
ss.close();

}

}


package cn.itcast.net.p4.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientDemo2 {

/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException,
IOException {

Socket socket = new Socket("192.168.0.101", 10002);

OutputStream out = socket.getOutputStream();

out.write("TCP演示:这里是客户端......".getBytes());

// 读取服务端返回的数据使用Socket读取流
InputStream in = socket.getInputStream();

byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf, 0, len);
System.out.println(text);

// 关闭资源(将连接断开)
socket.close();
}

}


文本转换客户端

package cn.itcast.net.p5.tcptest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TransServer {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

/*
* 转换服务端:
* 分析:
* 1.ServerSocket服务;
* 2.获取Socket对象;
* 3.源:Socket,读取客户端发过来需要转换的数据;
* 4.目的:显示在服务端控制台上;
* 5.将数据转成大写发回客户端;
* 6.关闭资源
*/

// 1.ServerSocket
ServerSocket ss = new ServerSocket(10004);

// 2.获取Socket对象
Socket s = ss.accept();

// 获取ip
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + ".....connected.");

// 3.获取Socket读取流,装饰
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));

// 4.获取Socket输出流并装饰
PrintWriter out = new PrintWriter(s.getOutputStream(), true);

String line = null;
while ((line = bufIn.readLine()) != null) {// 读取到数据,如果没有读到换行标记,则认为没有读取完毕
System.out.println(line);
out.println(line.toUpperCase());

// out.print(line.toUpperCase());//没有换行标记
// out.flush();//在不设置自动刷新时,需要调用flush()方法
}
s.close();
ss.close();
}

}


package cn.itcast.net.p5.tcptest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class TransClient {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

/*
* 思路:
* 客户端:
* 1.需要Socket端点;
* 2.客户端的数据源:键盘;
* 3.客户端的目的:Socket;
* 4.接收服务端的数据,源:socket;
* 5.将数据打印出来,目的:控制台;
* 6.在这些流中操作的数据,都是文本数据。
*
* 转换客户端:
* 1.创建Socket客户端对象;
* 2.获取键盘录入;
* 3.将录入的信息发送给Socket输出流;
*/

// 1.创建Socket对象
Socket socket = new Socket("192.168.0.101", 10004);

// 2.获取键盘录入
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));

// 3.目的是Socket输出流
// new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);// 自动刷新

// 4.Socket输入流,读取服务端返回的大写数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
socket.getInputStream()));

String line = null;
while ((line = bufr.readLine()) != null) {// 读取到数据,如果没有读到换行标记,则认为没有读取完毕
if ("over".equals(line))
break;
out.println(line);// 写入到PrintWriter中,需要刷新动作,才输出到Socket流中

// out.print(line);//没有换行标记
// out.flush();//在不设置自动刷新时,需要调用flush()方法

// 读取服务端发回的一行大写数据
String upperStr = bufIn.readLine();
System.out.println(upperStr);
}
socket.close();// 导致服务端结束
}

}


如果不刷新,则数据暂存在PrintWriter中,不输出到Socket输出流,需要使用flush()方法;
如果readLine()没有读到换行标记,则任务数据没有读取完毕,继续等待;

上传文本文件

package cn.itcast.net.p6.uploadtext;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class UploadServer {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

//1.创建ServerSocket服务端
ServerSocket ss=new ServerSocket(10005);

//2.获取Socket对象
Socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+"......connected.");

//3.获取客户端读取流
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));

//4.创建目的文件对象
BufferedWriter bufw=new BufferedWriter(new FileWriter("c:\\server.txt"));

String line=null;
while((line=bufIn.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}

PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("上传成功");

bufw.close();
s.close();
ss.close();

}

}


package cn.itcast.net.p6.uploadtext;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class UploadClient {

/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException,
IOException {

// 1.创建Socket对象
Socket s = new Socket("192.168.0.101", 10005);

// 2.创建源文件对象,源是文本文件
BufferedReader bufr = new BufferedReader(new FileReader(
"c:\\client.txt"));

// 3.目的是Socket输出流
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufr.readLine()) != null) {
out.println(line);
out.flush();
}
// out.println("over");
// 告诉服务端,客户端数据已经写完了
s.shutdownOutput();

// 4.读取Socket流,
BufferedReader bufIn = new BufferedReader(new InputStreamReader(
s.getInputStream()));

String str = bufIn.readLine();
System.out.println(str);

bufr.close();
s.close();

}

}


服务端多线程示例:

package cn.itcast.net.p1.uploadpic;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class UploadPicServer {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

// 1.创建TCP的Socket服务端
ServerSocket ss = new ServerSocket(10006);

while (true) {
// 2.获取客户端
Socket s = ss.accept();

new Thread(new UploadTask(s)).start();
}

// ss.close();

}

}


package cn.itcast.net.p1.uploadpic;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class UploadTask implements Runnable {

private Socket s;

public UploadTask(Socket s) {
this.s = s;
}

@Override
public void run() {

int count=0;
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "......connected.");

try {
// 3.读取客户端发来的数据
InputStream in = s.getInputStream();

// 4.将读取到的数据存储到一个文件中
File dir = new File("c:\\pic");
if (!(dir.exists())) {
dir.mkdirs();
}
File file = new File(dir, ip + ".jpg");

//如果文件已经存在于服务器端
while(file.exists()){
file =new File(dir,ip+"("+(++count)+").jpg");
}

FileOutputStream fos = new FileOutputStream(file);

byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}

// 给客户端发回:上传成功
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());

fos.close();
s.close();
} catch (IOException e) {
}
}

}


package cn.itcast.net.p1.uploadpic;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class UploadPicClient {

/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException,
IOException {

// 1.创建客户端
Socket s = new Socket("192.168.0.101", 10006);

// 2.读取客户端要上传的图片文件
FileInputStream fis = new FileInputStream("c:\\0.jpg");

// 3.获取Socket输出流,将读到的图片数据发送给服务端
OutputStream out = s.getOutputStream();

byte[] buf = new byte[1024];

int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
// 告诉服务端,数据发送完毕
s.shutdownOutput();

// 读取服务端发回的内容
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int lenIn = in.read(bufIn);
String text = new String(bufIn, 0, lenIn);
System.out.println(text);

fis.close();
s.close();
}

}


常见客户端和服务器
最常见的客户端:
浏览器:IE
最常见的服务端:
服务器:Tomcat

客户端和服务器端原理
1.自定义服务端,使用已有的客户端IE,了解客户端给服务器端发送了什么请求。

GET / HTTP/1.1 请求行:请求方式 /myweb/index.html 请求的资源路径 http协议版本
请求消息头,属性名:属性值
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: 192.168.0.101:9090
Connection: Keep-Alive
//请求头和请求体之间有一个空行,此行为空行
//请求体

模拟浏览器
//服务器发回的应答消息
HTTP/1.1 200 OK //应答行 http的协议版本,应答状态码,应答状态描述信息

//应答消息头。属性名:属性值
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"1807-1345210068813"
Last-Modified: Fri, 17 Aug 2012 13:27:48 GMT
Content-Type: text/html
Content-Length: 1807
Date: Fri, 17 Aug 2012 13:28:20 GMT
Connection: close
//空行
//应答体
<font color='red' size='7'>欢迎光临</font>

public final class URL extends Objectimplements Serializable
类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。

InputStream openStream()
打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。
打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。此方法是下面方法的缩写:
openConnection().getInputStream()

package cn.itcast.net.p2.ie_server;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class URLDemo {

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

String str_url = "http://192.168.0.101:8080/myweb/2.html?name=lisi";

URL url = new URL(str_url);

// System.out.println("getProtocol:"+url.getProtocol());
// System.out.println("getHost:"+url.getHost());
// System.out.println("getPath:"+url.getPath());
// System.out.println("getFile:"+url.getFile());
// System.out.println("getPath:"+url.getPath());
// System.out.println("getQuery:"+url.getQuery());

// 获取url对象的Url连接器对象,将连接封装成了对象:java中内置的可以解析具体协议的对象+socket
URLConnection conn = url.openConnection();

String value=conn.getHeaderField("Content-Type");//text/html

System.out.println(value);

//        System.out.println(conn);
// 输出:sun.net.www.protocol.http.HttpURLConnection:http://192.168.0.101:8080/myweb/2.html?name=lisi

// InputStream in=url.openStream();//打开到此 URL 的连接并返回一个用于从该连接读入的InputStream
// 打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。此方法是下面方法的缩写:openConnection().getInputStream()
InputStream in=conn.getInputStream();

byte[] buf=new byte[1024];
int len=in.read(buf);

String text=new String(buf,0,len);

System.out.println(text);//只有应答体,没有消息头

in.close();

}

}


网络架构
1.C/S Client/Server
缺点:
该结构的软件,客户端和服务端都需要编写;
开发成本较高,维护较为麻烦;
优点:
客户端在本地,可以分担一部分运算;

2.B/S Browser/Server
缺点:
所有运算都在服务器端完成;
优点:
该结构的软件,只开发服务器端,不开发客户端;因为客户端直接由浏览器取代;
开发成本相对较低,维护更为简单;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: