软件结构
C/S结构:Cilent/Server结构,是指客户端和服务器,例如QQ。
B/S结构:Browser/Server结构,是指浏览器和服务器结构,例如火狐。
网络编程:一定的协议下,实现两台计算机的通信的程序
网络通信协议
计算机进行连接和通讯需要遵守一定的规则,就是网络通信协议。
TCP/IP协议(传输控制协议/因特网互联协议Transmission Control Protocol/Internet Protocol)最基本的协议,定义了
计算机如何连入因特网,以及数据如何在他们之间传输的标准。
协议分类
UDP:用户数据报协议(User Datagram Protocol),无连接通讯协议,耗资源小,效率高,但容易丢包。例如QQ。
TCP: 传输控制协议(Transmission Control Protocol),面向连接的通讯协议,传送数据前,客户端和服务器三次握手。第一次握手:客户端向服务器端发送连接请求,第二次握手:服务器端回应收到,第三次握手:客户端再次发送信息确认连接。例如文件的下载,网页的浏览。安全,但效率不太高。
网络编程三要素
协议
规则
IP地址
IPv4:是一个32位的二进制,通常被分为4个字节,例如192.168.65.100,最多42亿个。
常用命令:ipconfig
检查网络是否连接:ping 220.181.57.210
本机ip地址:ping 127.0.0.1 ping localhost
端口号:是一个逻辑端口,当我们使用网络软件一打开,那么操作系统就会为网络软件分配一个随机的端口号,或者软件打开的时候和系统要指定的端口号,端口号是由两个字节组成,取值范围在0-65535之间。1024之前的端口号已经无法使用。例如:192.168.1.200:5000。
常用的端口号: 1.80端口号 www.baidu.com:80
2.数据库 mysql:3306 oracle:1521
3.Tomact:8080
Socket
Socket就是为了网络服务提供的一种机制
通讯的两端都有Socket
网络通讯其实就是Socke间的通讯
数据在两个Socket间通过IO传输
UPD通讯
DatagramSocket
此类表示用于发送和接收数据报数据包的套接字。
构造数据报套接字并将其绑定到本地主机上的任何可用端口。
DatagramPacket
数据报包用于实现无连接分组传送服务。 仅基于该数据包中包含的信息,每个消息从一台机器路由到另一台机器。 从一台机器发送到另一台机器的多个分组可能会有不同的路由,并且可能以任何顺序到达。 包传送不能保证。
发送端
package com.monfolld.net.UPD;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPSendDemo {
public static void main(String[] args)throws IOException {
System.out.println("发送端启动....");
/*创建UPD传输的发送端
* 思路:
* 1.创建upd的socket服务
* 2.将要发送的数据封装到数据包中
* 3.通过upd的socket服务将数据包发送出去
* 4.关闭socket服务*/
DatagramSocket ds=new DatagramSocket(8888);
String str="upd输出演示:哥们来了";
byte[] buf=str.getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length, InetAddress.getByName("169.254.12.142"),10000);
ds.send(dp);
ds.close();
}
}
接收端
package com.monfolld.net.UPD;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPReceDemo {
public static void main(String[] args)throws IOException {
System.out.println("接收端启动....");
/*建立UDP接收端的思路:
* 1.检录udp,socket服务
* 2.创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析这些数据
* 3.使用socket服务的receive方法将接收到的数据存储到数据包中
* 4.通过数据包的方法解析数据包中的数据
* 5.关闭资源
**/
DatagramSocket ds=new DatagramSocket(10000);
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
System.out.println("接收端启动....");
ds.receive(dp);
System.out.println("接收端启动....");
String ip=dp.getAddress().getHostAddress();
int prot=dp.getPort();
String text=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+prot+":"+text);
ds.close();
}
}
聊天程序
发送端类
package com.monfolld.net.UPD;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPSendTest implements Runnable {
private DatagramSocket ds;
public UDPSendTest(DatagramSocket ds){
this.ds=ds;
}
public void run(){
try {
DatagramSocket ds=new DatagramSocket(8888);
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("169.254.12.142"),10000);
ds.send(dp);
}
}catch (Exception e){
}
}
}
接收端类
package com.monfolld.net.UPD;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPReceTest implements Runnable{
private DatagramSocket ds;
public UDPReceTest(DatagramSocket ds){
this.ds=ds;
}
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 prot=dp.getPort();
String text=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+prot+":"+text);
}
}catch (Exception e){
}
}
}
聊天室
package com.monfolld.net.UPD;
import java.io.IOException;
import java.net.DatagramSocket;
public class ChatDemo {
public static void main(String[] args)throws IOException {
DatagramSocket send=new DatagramSocket();
DatagramSocket rece=new DatagramSocket(10000);
new Thread(new UDPSendTest(send)).start();
new Thread(new UDPReceTest(rece)).start();
}
}
TCP通讯程序
客户端代码实现
package com.monfolld.net;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*TCP通讯的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器会写的数据
* 表示客户端的类:
* java.net.Socket:此类实现客户端套接字,套接字是两台机器通讯的端点
* 套接字:包含了IP地址和编口号的网路单位
*
* 构造方法:
* Socket(String host, int port)
创建流套接字并将其连接到指定主机上的指定端口号。
* 参数:服务器主机的名称/服务器的IP地址,服务器的端口号
* 成员方法:
* OutoutStream getOutputStream();
* InputStream getInputStream();
* void close();//关闭套接字
* 实现步骤:
* 1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号
* 2.使用Socket对象中的getOutputStream()获取网络字节输出流OutoutStream对象
* 3.使用网络字节输出流OutoutStream对象中的write,给服务器发送数据
* 4.使用Socket对象中的getInputStream()获取网络字节输出流InputStream对象
* 5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
* 6.释放资源(Socket)
* 注意:
* 1.客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
* 2.当我们创建客户端对象Socket的时候,就会请求服务器和服务器经过三次握手建立连接通路,
* 这时如果服务器没有启动,那么久会抛出异常*/
public class TCPCilent {
public static void main(String[] args)throws IOException {
Socket socket=new Socket("127.0.0.1",8888);
OutputStream os=socket.getOutputStream();
os.write("你好服务器".getBytes());
InputStream is=socket.getInputStream();
byte[] bytes=new byte[1024];
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));
socket.close();
}
}
服务器端代码实现
package com.monfolld.net;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*TCP通讯的服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据
* 表示服务器的类:java.net.ServerSocket此类实现服务器套接字
*
* 构造方法:
* ServerSocket(int port)创建绑定到指定端口的服务器套接字。
*服务器必须明确知道哪个客户端请求的服务器,所以可以使用accept方法获取请求到的客户端对象Socket
* 成员方法:
* Socket accept()侦听并接受此套接字的连接
* 服务器的实现步骤:
* 1.创建服务器ServerSocket对象和系统要指定的端口号
* 2.使用ServerSocket对象中的accept,获取到请求的客户端对象Socket
* 3.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
* 4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
* 5.使用Socket对象中的方法getOutoutStream()获取网络字节输出流OutputStream对象
* 6.使用网络字节输出流OutputStream对象中的方法write,给客户端回写数据
* 7.释放资源(Socket)*/
public class TCPServer {
public static void main(String[] args)throws IOException {
ServerSocket serverSocket=new ServerSocket(8888);
Socket socket=serverSocket.accept();
InputStream is=socket.getInputStream();
byte[] bytes=new byte[1024];
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));
OutputStream os=socket.getOutputStream();
os.write("收到谢谢".getBytes());
socket.close();
serverSocket.close();
}
}
文件上传案例
客户端代码实现
package com.monfolld.net.FileUpload;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*文件上传案例的客户端:读取本地文件,上传到服务器,读取服务器回写的数据
* 明确:
* 数据源:d:\\1.jpg
* 目的地:服务器
* 实现步骤:
* 1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
* 2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
* 3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
* 4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
* 5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
* 6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
* 7.使用网络字节输入流InputStream对象中的方法read读取服务回写的数据
* 8.释放资源*/
public class TCPClient {
public static void main(String[] args)throws IOException {
FileInputStream fis=new FileInputStream("d:\\1.txt");
Socket socket=new Socket("127.0.0.1",8888);
OutputStream os=socket.getOutputStream();
int len=0;
byte[] bytes=new byte[1024];
while ((len=fis.read(bytes))!=-1){ //read()读取本地上传文件,结束标记是-1
os.write(bytes,0,len); //但while循环不会读取到-1,那么也不会把结束标识写给服务器
} //所以需要shutdownOutput(禁用此套接字的输出流)方法结束
socket.shutdownOutput();//上传完以后,终止read读取不停止,防止while进入死循环
InputStream is=socket.getInputStream();
while ((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
fis.close();
socket.close();
}
}
服务器端代码实现
package com.monfolld.net.FileUpload;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*文件上传案例服务器端:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写"上传成功"
明确:
数据源:客户端上传的文件
目的地:服务器的硬盘 d:\\upload\\1.jpg
实现步骤
1.创建一个服务器ServerSocket对象,和系统要指定的端口号
2.使用ServerSocket对象中的方法accept,获取到请求的客户端Scoket对象
3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
4.判断d:\\upload文件夹是否存在,不存在则创建
5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
6.使用网络字节输入流InputStream中的方法read,读取客户端上传的文件
7.使用本地字节输出流FileOutputStream对象中的方法write,吧独到的文件保存到服务器的硬盘上
8.使用Scoket对象中的getOutputStream,获取到网络字节输出流OutputStream对象
9.使用网咯字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
10.释放资源(FileOutoutStream,Socket,ServerSocket)
*/
public class TCPServer {
public static void main(String[] args)throws IOException {
ServerSocket serverSocket=new ServerSocket(8888);
Socket socket=serverSocket.accept();
InputStream is=socket.getInputStream();
File file=new File("d:\\upload");
if (!file.exists()){
file.mkdirs();
}
FileOutputStream fos=new FileOutputStream(file+"\\1.txt");
int len=0;
byte[] bytes=new byte[1024];
while ((len=is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
serverSocket.close();
}
}
文件上传案例优化
服务器点优化就够了
package com.monfolld.net.FileUploadp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class TCPServerp {
public static void main(String[] args)throws IOException {
ServerSocket serverSocket=new ServerSocket(8888);
/*让服务器一直处于监听状态(死循环accept方法)
* 有一个客户端上传文件,就保存一个文件*/
new Thread(new Runnable() {
@Override
public void run() {
try {
//完成文件的上传
while (true) {
Socket socket = serverSocket.accept();
/*使用多线程计数,提高程序的效率
* 有一个客户端就上传文件,就开启一个线程,完成文件的上传*/
InputStream is = socket.getInputStream();
File file = new File("d:\\upload");
if (!file.exists()) {
file.mkdirs();
}
/*自定义一个文件的命名跪着:防止同名的文件被覆盖
* 规则:域名+毫秒值+随机数*/
String filenmae = "itcast" + System.currentTimeMillis() + new Random().nextInt(99999) + ".jpg";
FileOutputStream fos = new FileOutputStream(file + "\\" + filenmae);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
}
}catch (IOException e){
System.out.println(e);
}
}
} ).start();
}
//服务器就不用关闭
//serverSocket.close();
}
B\S服务器
网站浏览服务器
服务器端
package com.monfolld.net.BSTCP;
import com.sun.org.apache.bcel.internal.generic.NEW;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws IOException {
//创建一个服务器ServerSocket,和系统要指定的端口号
ServerSocket server = new ServerSocket(8080);
/*浏览器解析服务器回写html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
* 我们就让服务器一直处于监听状态,客户端请求一次服务器就会写一次*/
while (true){
//使用accept方法获取到请求的客户端对象(浏览器)
Socket socket = server.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
//使用Socket对象中的getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
/*byte[] bytes=new byte[1024];
int len=0;
while ((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}*/
//把is网络字节输入流对象,转换为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//把客户端请求信息的第一行读取出来 GET /11_Net/web/index.html
String line = br.readLine();
//吧读取的信息进行切割,只要中间部分
String[] arr = line.split(" ");
String htmlpath = arr[1].substring(1);
//创建一个本地字节输入流,构造方法中绑定要读取的html路径
FileInputStream fis = new FileInputStream(htmlpath);
//使用Socket中的getOutputStream获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//写入Http协议响应头,固定写法
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
//必须要写入空行,否则浏览器不解析
os.write("\r\n".getBytes());
//一读一写复制文件,吧服务器读取的html文件写回客户端
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
fis.close();
socket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}).start();
}
//server.close();
}
}