Java程序设计实验 实验五
课程:Java程序设计实验 班级:1353 姓名:符余佳源 学号:20135321
成绩: 指导教师:娄嘉鹏 实验日期:2015.6.9
实验密级:无 预习程度: 实验时间:15:30~18:00
仪器组次: 21 必修/选修: 选修 实验序号:5
实验名称:TCP传输及加解密
产品托管地址:http://git.shiyanlou.com/20135321/shiyanlou_cs212
实验内容:
1.运行教材上TCP代码,结对进行,一人服务器,一人客户端;
2.利用加解密代码包,编译运行代码,一人加密,一人解密;
3.集成代码,一人加密后通过TCP发送;
注:加密使用AES或者DES/AES或者DES加密密钥key并发送,使用服务器的公钥加密/公钥算法使用RSA或DH/检验发送信息的完整性使用MD5或者SHA3;
4.完成Blog。
实验仪器:
名称 |
型号 |
数量 |
PC |
ACER |
1 |
虚拟机 |
实验楼 |
1 |
一.实验步骤
(一)在进行实验之前,我花出一定的时间了解了AES及DES算法的相关内容,并再将JAVA的一些常用的语句进行了一定的回顾,为本次实验奠定一定的基础。
我(20135321)在本次实验中主要负责服务器端,我的搭档符运锦(20135323)负责客户端,他的博客园地址为:http://www.cnblogs.com/20135323fuyunjin
(二)回顾TCP
服务器端代码:
package chapter9;
import java.io.*;
import java.net.*;
public class ServerTest {
public static final int PORT=8080;
public static void main(String[] args)throws IOException{
ServerSocket s=new ServerSocket(PORT);
System.out.println("Started:"+s);
try{
Socket socket=s.accept();
try{
System.out.println("Connection accepted:"+socket);
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
while(true){
String str=in.readLine();
if(str.equals("END"))
break;
System.out.println("Echoing:"+str);
out.println(str);
}
}finally{
System.out.println("closing...");
socket.close();
}
}finally{
s.close();
}
}
}
客户端代码:
package chapter9;
import java.io.*;
import java.net.*;
public class ClientTest {
public static void main(String[] args)throws IOException{
InetAddress addr=InetAddress.getByName(null);
System.out.println("addr="+addr);
Socket socket=new Socket(addr,ServerTest.PORT);
try{
System.out.println("socket="+socket);
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
for(int i=0;i<10;i++){
out.println("howdy"+i);
String str=in.readLine();
System.out.println(str);
}
out.println("END");
}finally{
System.out.println("closing...");
socket.close();
}
}
}
注意:要先运行服务器端代码再运行客户端代码
运行结果截图如下:
(三)前期知识准备
什么是客户端?
客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务端互相配合运行。因特网发展以后,较常用的用户端包括了如万维网使用的网页浏览器,收寄电子邮件时的电子邮件客户端,以及即时通讯的客户端软件等。对于这一类应用程序,需要网络中有相应的服务器和服务程序来提供相应的服务,如数据库服务,电子邮件服务等等,这样在客户机和服务器端,需要建立特定的通信连接,来保证应用程序的正常运行。
原理:
客户端及伺服端的关系不见得一定建立在两台分开的机器上,同一台机器中也有这种主从关系的存在。提供服务的伺服端及接受服务的客户端也有可能都在同一台机器上,例如我们在提供网页的服务器上执行浏览器浏览本机所提供的网页,这样在同一台机器上就同时扮演伺服端及客户端。
什么是服务器端?
服务器端(Server)是指在网络编程中被动等待连接的程序,服务器端一般实现程序的核心逻辑以及数据存储等核心功能。服务器端的编程步骤和客户端不同,是由四个步骤实现,依次是:
①监听端口: 服务器端属于被动等待连接,所以服务器端启动以后,不需要发起连接,而只需要监听本地计算机的某个固定端口即可。这个端口就是服务器端开放给客户端的端口,服务器端程序运行的本地计算机的IP地址就是服务器端程序的IP地址。
②获得连接:当客户端连接到服务器端时,服务器端就可以获得一个连接,这个连接包含客户端的信息,例如客户端IP地址等等,服务器端和客户端也通过该连接进行数据交换。一般在服务器端编程中,当获得连接时,需要开启专门的线程处理该连接,每个连接都由独立的线程实现。
③交换数据:服务器端通过获得的连接进行数据交换。服务器端的数据交换步骤是首先接收客户端发送过来的数据,然后进行逻辑处理,再把处理以后的结果数据发送给客户端。简单来说,就是先接收再发送,这个和客户端的数据交换数序不同。其实,服务器端获得的连接和客户端连接是一样的,只是数据交换的步骤不同。当然,服务器端的数据交换也是可以多次进行的。
④关闭连接:当服务器程序关闭时,需要关闭服务器端,通过关闭服务器端使得服务器监听的端口以及占用的内存可以释放出来,实现了连接的关闭。
什么是TCP?
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内[1] 另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。[1]
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元([1] MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体[1] 的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
在数据正确性与合法性上,TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和;同时可以使用md5认证对数据进行加密。
(四)具体操作
1.运行DES加密代码
import java.io.*;
import javax.crypto.*;
public class Skey_DES{
public static void main(String args[]) throws Exception{
KeyGenerator kg=KeyGenerator.getInstance("DESede");
kg.init(168);
SecretKey k=kg.generateKey( );
FileOutputStream f=new FileOutputStream("key1.dat");
ObjectOutputStream b=new ObjectOutputStream(f);
b.writeObject(k);
}
}
设置加解密文件
import java.io.*;
import java.security.*;
public class Skey_kb{
public static void main(String args[]) throws Exception{
FileInputStream f=new FileInputStream("key1.dat");
ObjectInputStream b=new ObjectInputStream(f);
Key k=(Key)b.readObject( );
byte[ ] kb=k.getEncoded( );
FileOutputStream f2=new FileOutputStream("keykb1.dat");
f2.write(kb);
// 打印密钥编码中的内容
for(int i=0;i<kb.length;i++){
System.out.print(kb[i]+",");
}
}
}
运行截图:
2.原理解释:
(1)throws Exception {}//表示该方法可能产生异常,并使用throws声明异常,//则该方法产生异常也不必捕获
(2)例如想用“hello”作为密钥利用DES进行加密和解密:
String keyString=”hello”;
byte[]keyData=keyString.getBytes();
secretKey myDeskey=new SecretKeySpec(keyData,”DES”);
(3) 获取密钥生成器
KeyGenerator kg=KeyGenerator.getInstance("DESede");
Java中KeyGenerator类中提供了创建对称密钥的方法。Java中的类一般使用new操作符通过构造器创建对象,但KeyGenerator类不是这样,它预定义了一个静态方法getInstance(),通过它获得KeyGenerator类型的对象。这种类成为工厂类或工厂。
方法getInstance( )的参数为字符串类型,指定加密算法的名称。
(4)初始化密钥生成器
kg.init(168);
该步骤一般指定密钥的长度。如果该步骤省略的话,会根据算法自动使用默认的密钥长度。指定长度时,若第一步密钥生成器使用的是“DES”算法,则密钥长度必须是56位;若是“DESede”,则可以是112或168位,其中112位有效;若是“AES”,可以是128, 192或256位。
(5)生成密钥SecretKey k=kg.generateKey( );
使用第一步获得的KeyGenerator类型的对象中generateKey( )方法可以获得密钥。其类型为SecretKey类型,可用于以后的加密和解密。
(6)通过对象序列化方式将密钥保存在文件中
FileOutputStream f=new FileOutputStream("key1.dat");
ObjectOutputStream b=new ObjectOutputStream(f); b.writeObject(k);
ObjectOutputStream类中提供的writeObject方法可以将对象序列化,以流的方式进行处理。这里将文件输出流作为参数传递给ObjectOutputStream类的构造器,这样创建好的密钥将保存在文件key1.dat中。
(五)代码实现
在本次实验中,我们采取了一台计算机进行结对试验。当运用一台计算机进行本次实验室,只需要开出两个CMD窗口即可。
服务器代码(20135321余佳源):
import java.net.*;
import java.io.*;
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import java.security.interfaces.*;
import java.math.*;
public class ComputeTCPServer{
public static void main(String srgs[]) throws Exception {
ServerSocket sc = null;//空代表可以使用默认值
Socket socket=null;
try {
sc= new ServerSocket(2123);//创建服务器套接字
System.out.println("端口号:" + sc.getLocalPort());
System.out.println("服务器已经启动...");
socket = sc.accept(); //等待客户端连接
System.out.println("已经建立连接");
//获得网络输入流对象的引用
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
////获得网络输出流对象的引用
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
String aline2=in.readLine();//读取客户端传送来的数据
BigInteger c=new BigInteger(aline2);
FileInputStream f=new FileInputStream("Skey_RSA_priv.dat");//从Skey_RSA_priv.dat中获得输入字节
ObjectInputStream b=new ObjectInputStream(f);
RSAPrivateKey prk=(RSAPrivateKey)b.readObject( );//RSA 专用密钥的接口
BigInteger d=prk.getPrivateExponent();//进行大数运算
BigInteger n=prk.getModulus();
BigInteger m=c.modPow(d,n);
byte[] keykb=m.toByteArray();
String aline=in.readLine();//读取客户端传送来的数据
byte[] ctext=parseHexStr2Byte(aline);
Key k=new SecretKeySpec(keykb,"DESede");//使用SecretKeySpec类来根据一个字节数组构造一个 SecretKey.
//仅对能表示为一个字节数组并且没有任何与之相关联的钥参数的原始密钥有用,如,DES
Cipher cp=Cipher.getInstance("DESede");//加密和解密
cp.init(Cipher.DECRYPT_MODE, k);
byte []ptext=cp.doFinal(ctext);
String p=new String(ptext,"UTF8");
System.out.println("从客户端接收到信息为:"+p); //通过网络输出流返回结果给客户端
String aline3=in.readLine();
String x=p;
MessageDigest m2=MessageDigest.getInstance("MD5");//为应用程序提供信息摘要算法的功能,如 MD5算法
//是单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。
m2.update(x.getBytes( ));
byte a[ ]=m2.digest( );
String result="";
for (int i=0; i<a.length; i++){
result+=Integer.toHexString((0x000000ff & a[i]) |
0xffffff00).substring(6);
}
System.out.println(result);
if(aline3.equals(result)){
System.out.println("匹配成功");
}
out.println("匹配成功");
out.close();
in.close();
sc.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++) {
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1 ), 16); //将String字符类型数据转换为Integer整型数据
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
客户端代码(20135323符运锦):
import java.net.*;
import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.spec.*;
import javax.crypto.interfaces.*;
import java.security.interfaces.*;
import java.math.*;
public class ComputeTCPClient {
public static void main(String srgs[]) throws Exception{
try {
KeyGenerator kg=KeyGenerator.getInstance("DESede");//KeyGenerator类提供(对称)密钥生成器的功能
//密钥生成器是使用此类的某个 getInstance 类方法构造的
//方法getInstance( )的参数为字符串类型,指定加密算法的名称
kg.init(168); //初始化指定密钥的长度
SecretKey k=kg.generateKey( );//秘密(对称)密钥。实现此接口的密钥以其编码格式返回字符串,并返回作为 getEncoded 方法调用结果的原始密钥字节
byte[] ptext2=k.getEncoded();//设置一个字节数组承载原始密钥字节
//创建连接特定服务器的指定端口的Socket对象
Socket socket = new Socket("192.168.1.115", 2123);//该IP地址是寝室网IP
//获得从服务器端来的网络输入流
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//获得从客户端向服务器端输出数据的网络输出流
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
//创建键盘输入流,以便客户端从键盘上输入信息
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
FileInputStream f3=new FileInputStream("Skey_RSA_pub.dat");
ObjectInputStream b2=new ObjectInputStream(f3);
RSAPublicKey pbk=(RSAPublicKey)b2.readObject( );
BigInteger e=pbk.getPublicExponent();
BigInteger n=pbk.getModulus();
BigInteger m=new BigInteger(ptext2);
BigInteger c=m.modPow(e,n);
String cs=c.toString( );
out.println(cs); //通过网络传送到服务器
System.out.print("请输入待发送的数据:");
String s=stdin.readLine(); //从键盘读入待发送的数据
Cipher cp=Cipher.getInstance("DESede");//DES算法的解码过程
cp.init(Cipher.ENCRYPT_MODE, k);//DES算法的解码过程
byte ptext[]=s.getBytes("UTF8");//DES算法的解码过程
byte ctext[]=cp.doFinal(ptext);//DES算法的解码过程
String str=parseByte2HexStr(ctext);//DES算法的解码过程
out.println(str); //通过网络传送到服务器
String x=s;
MessageDigest m2=MessageDigest.getInstance("MD5");//MessageDigest类为应用程序提供信息摘要算法的功能如MD5算法
m2.update(x.getBytes( ));
byte a[ ]=m2.digest( );
String result="";
for (int i=0; i<a.length; i++){
result+=Integer.toHexString((0x000000ff & a[i]) |
0xffffff00).substring(6);////以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。
}
System.out.println(result);
out.println(result);
str=in.readLine();//从网络输入流读取结果
System.out.println( "从服务器接收到的结果为:"+str); //输出服务器返回的结果
}
catch (Exception e) {
System.out.println(e);
}
finally{
}
}
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF); //返回的字符串表示的无符号整数参数所表示的值以十六进制(基数为16)
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++) {
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); //将String字符类型数据转换为Integer整型数据
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); //将String字符类型数据转换为Integer整型数据
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
(六)整合
1.寝室网IP地址:
整合操作截图:
(七)PSP时间
步骤 |
耗时 |
百分比 |
需求分析 |
50min |
16.1% |
设计 |
60min |
19.3% |
代码实现 |
120mn |
38.7% |
测试 |
20min |
6.5% |
分析总结 |
60min |
19.3% |
(八)遇到的问题
1.一开始并没有想着建立两台laptop之间的互用局域网导致不能够实现服务器端和客户端的互联
解决方案:用电脑放出wifi或者手机开出热点或者使用寝室里的路由器进行局域传输。
2.在单独一台laptop上进行模拟实验的时候,一开始没有想到使用两个CMD窗口来操作,单独一个eclipse也不能实现得了服务器端和客户端的联系。
解决方案:经过符运锦的提醒点拨就想到了使用两个CMD窗口,成功实现了模拟互联。
(九)实验体会及感想
这是第四次java实验,也是本学期最后一次的java实验了。相对比于前三次的实验,这次实验更着重的是对代码的整合和搭配,还有在一定程度上考察了我们对密码学知识的理解。同样的这是一次结对编程实验,领航员和驾驶员都很重要,两者也可以互换角色,这一点我深有体会,因为一开始我是觉得我可以胜任很大部分的代码工作,到后来却是符运锦同学把握点拨出了实验的重点。不管如何,我们还是在实验中收获颇丰,组合代码也是一个java程序员应该具备的技能,所以我感到很幸运。
Java程序设计实验 实验五的更多相关文章
- 20145205 《Java程序设计》实验报告五:Java网络编程及安全
20145205 <Java程序设计>实验报告五:Java网络编程及安全 实验要求 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.客户端中输入明文,利用DES算法加密,D ...
- 20145213《Java程序设计》实验五Java网络编程及安全
20145213<Java程序设计>实验五Java网络编程及安全 实验内容 1.掌握Socket程序的编写. 2.掌握密码技术的使用. 3.设计安全传输系统. 实验预期 1.客户端与服务器 ...
- 20145206《Java程序设计》实验五Java网络编程及安全
20145206<Java程序设计>实验五 Java网络编程及安全 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验步骤 我和201451 ...
- 20145308刘昊阳 《Java程序设计》实验五报告
20145308刘昊阳 <Java程序设计>实验五 Java网络编程及安全 实验报告 实验名称 Java网络编程及安全 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: ...
- 20145330《Java程序设计》第五次实验报告
20145330<Java程序设计>第五次实验报告 实验五 Java网络编程及安全 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统 4.结队伙伴 ...
- 20145320《Java程序设计》第五次实验报告
20145320<Java程序设计>第五次实验报告 北京电子科技学院(BESTI)实验报告 课程:Java程序设计 班级:1453 指导教师:娄嘉鹏 实验日期:2016.05.06 18: ...
- 20145225《Java程序设计》 实验五 Java网络编程及安全
20145225<Java程序设计> 实验五 Java网络编程及安全 实验报告 一.实验内容 基于Java Socket实现安全传输. 基于TCP实现客户端和服务器,结对编程一人负责客户端 ...
- 20145222黄亚奇《Java程序设计》实验五实验报告
20145222 <Java程序设计>实验五实验报告 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验步骤 本次实验我的结对编程对象是20 ...
- 20145315 《Java程序设计》实验五实验报告
20145315 <Java程序设计>实验五实验报告 实验五 Java网络编程 我负责服务器部分,王嘉澜负责客户端部分:http://www.cnblogs.com/SJZGM10/p/5 ...
- 20145211 《Java程序设计》实验报告五————Java网络编程及安全实验报告
实验内容 1.掌握Socket程序的编写: 掌握密码技术的使用: 设计安全传输系统. 实验步骤 这一部分是与我的partner合作的,详见他的博客- [20145326 <Java程序设计> ...
随机推荐
- 拥抱.NET Core系列:MemoryCache 缓存选项 (转载)
阅读目录 MSCache项目 MemoryCacheOptions ExpirationScanFrequency SizeLimit CompactionPercentage 写在最后 在上一篇 ” ...
- OpenGL ES天空盒子效果
一.理解 利用GLKBaseEffect,自定义顶点着色器和片元着色器,结合天空盒子,展示效果 二.技术代码 CCSkyBoxEffect:天空盒子效果类: CCSkyboxShader.vsh:顶点 ...
- 四层and七层负载均衡
四层负载/七层负载 在常规运维工作中,经常会运用到负载均衡服务.负载均衡分为四层负载和七层负载,那么这两者之间有什么不同? 废话不多说,详解如下: 1. 什么是负载均衡 1)负载均衡(Load ...
- Python的scrapy之爬取6毛小说网的圣墟
闲来无事想看个小说,打算下载到电脑上看,找了半天,没找到可以下载的网站,于是就想自己爬取一下小说内容并保存到本地 圣墟 第一章 沙漠中的彼岸花 - 辰东 - 6毛小说网 http://www.6ma ...
- 使用zabbix发送邮件的简易设置流程(存档用)
1.安装邮件软件 (一般默认安装sendmail,这样apache也不用重新设置.) $sudo yum install sendmail 2.在zabbix上设置发送邮件用的本地邮箱 选择管理-&g ...
- x01.calc: 编程语言
想写终极程序,大都去写操作系统或编程语言了.编程语言可以极其复杂如C,也可以极简,只处理加减乘除如 calc. 1. 词法分析 %{ #include <stdio.h> #include ...
- tkinter的GUI设计:界面与逻辑分离(一)-- 初次见面
PyQt实现界面与逻辑分离的设计很是方便,详情可以见我的第一篇博文. 不过本文将使用python的标准库 tkinter,来实现界面与逻辑分离的GUI 设计. 我们来设计一个很简单的程序: 目的:长度 ...
- 从零开始自学 Java Web
目录: 1.Java JDK下载安装及配置 2.eclipse下载与安装并测试 3.eclipse快捷键 4.Tomcat 下载与安装 5.Tomcat部署Web应用 6.Eclipse中配置Tomc ...
- flask 实现异步非阻塞----gevent
我们都知道,flask不支持异步非阻塞的请求,我们可以创建一个新项目去测试一下,推荐大家使用pycharm去开发我们的flask 使用特别的方便. rom flask import Flask im ...
- mysql 中sql语句关键字的书写顺序与执行顺序
书写顺序: select -> from -> where -> group by -> having -> order by 执行顺序: from -> wher ...