a Socket编程中的一个秘密类

Java网络编程入门
本文介绍如何使用Java.net包中的URLConnection类轻松实现网络资源的获取,通过示例代码详细讲解了如何连接服务器并请求文档。
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> 介绍   Java平台在java.net包里来实现Socket。在这本文中,我们将使用Java.net包中的下面三个类来工作:   ?URLConnection   ?Socket   ?ServerSocket   在java.net包里包含有更多的类,但是这些是你最经常遇见的,让我们从URLConnection开始,这个类提供了在你的java代码里使用Socket的方法而无需了解Socket的底层机制。   甚至不用尝试就可以使用sockets   连接到一个URL包括以下几个步骤:   ?创建一个URLConnection   ?用不同的setter方法配置它   ?连接到URLConnection   ?与不同的getter方法进行交互 下面,我们来用一些例子示范怎样使用URLConnection从一台服务器上请求一份文档。 URLClient类 我们将从URLClient类的结构开始讲起。 import java.io.*; import java.net.*; public class URLClient {  protected URLConnection connection;  public static void main(String[] args) {}  public String getDocumentAt(String urlString) {} }   注意:必须要先导入java.net和java.io包才行   我们给我们的类一个实例变量用于保存一个URLConnection   我们的类包含一个main()方法用于处理浏览一个文档的逻辑流(logic flow),我们的类还包含了getDocumentAt()方法用于连接服务器以及请求文档,下面我们将探究这些方法的细节。 浏览文档   main()方法用于处理浏览一个文档的逻辑流(logic flow): public static void main(String[] args) {  URLClient client = new URLClient();  String yahoo = client.getDocumentAt("http://www.yahoo.com");  System.out.println(yahoo); }   我们的main()方法仅仅创建了一个新的URLClient类的实例并使用一个有效的URL String来调用getDocumentAt()方法。当调用返回文档,我们把它储存在一个String里并把这个String输出到控制台上。然而,实际的工作是getDocumentAt()方法当中完成的。   从服务器上请求一份文档   getDocumentAt()方法处理在实际工作中如何从web上得到一份文档: public String getDocumentAt(String urlString) {  StringBuffer document = new StringBuffer();  try {   URL url = new URL(urlString);   URLConnection conn = url.openConnection();   BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));   String line = null;   while ((line = reader.readLine()) != null)    document.append(line " ");    reader.close();  } catch (MalformedURLException e) {   System.out.println("Unable to connect to URL: " urlString);  } catch (IOException e) {   System.out.println("IOException when connecting to URL: " urlString);  }  return document.toString(); }   getDocumentAt()方法有一个String类型的参数包含我们想得到的那份文档的URL。我们先创建一个StringBuffer用于保存文档的行。接着,我们用传进去的参数urlString来创建一个新的URL。然后,我们创建一个URLConnection并打开它: URLConnection conn = url.openConnection();   一旦有了一个URLConnection,我们就获得它的InputStream并包装成InputStreamReader,然后我们又把它进而包装成BufferedReader以至于我们能够读取从服务器获得的文档的行,我们在java代码中处理socket的时候会经常使用这种包装技术。在我们继续学习之前你必须熟悉它: BufferedReader reader =new BufferedReader(new InputStreamReader(conn.getInputStream()));   有了BufferedReader,我们能够容易的读取文档的内容。我们在一个while...loop循环里调用reader上的readline()方法: String line = null; while ((line = reader.readLine()) != null) document.append(line " ");   调用readLine()方法后从InputStream传入行终止符(例如换行符)时才产生阻塞。如果没有得到,它将继续等待,当连接关闭时它才会返回null,既然这样,一旦我们获得一个行,我们连同一个换行符把它追加到一个调用的文档的StringBuffer上。这样就保留了从服务器上原文档的格式。   当我们读取所有行以后,我们应该关闭BufferedReader: reader.close();   如果提供给urlString的URL构造器无效,则将会抛出一个MalformedUR特拉LException异常。同样如果产生了其他的错误,例如从连接获取InputStream时,将会抛出IOException。   总结   1.用一个你想连接的资源的有效的url String来实例化URL   2.连接到指定URL   3.包装InputStream为连接在BufferedReader以至于你可以读取行   4.用你的BufferedReader读取文档内容   5.关闭BufferedReader
要使用Socket编程来实现通信,可以将上述代码分别放在两个程序中,一个程序作为Alice,另一个程序作为Bob,然后通过Socket来传输数据。下面是一个简单的示例代码,其中假设Alice和Bob分别运行在两台计算机上,它们的IP地址分别为192.168.1.100和192.168.1.101。 Alice端代码: ```python import random import hashlib from Crypto.Cipher import DES import socket # Diffie-Hellman密码协商 def diffie_hellman(p, g, a, b): A = pow(g, a, p) B = pow(g, b, p) K = pow(B, a, p) return K # 生成一个DES加密密钥 def generate_key(): key = '' for i in range(8): key += chr(random.randint(0, 255)) return key # 加密 def encrypt(key, data): cipher = DES.new(key, DES.MODE_ECB) return cipher.encrypt(data) # 解密 def decrypt(key, data): cipher = DES.new(key, DES.MODE_ECB) return cipher.decrypt(data) # 计算MD5哈希值 def hash(data): h = hashlib.md5() h.update(data) return h.hexdigest() # 数字签名 def sign(private_key, data): h = hash(data) signature = pow(int(h, 16), private_key, p) return signature # 验证签名 def verify(public_key, signature, data): h = hash(data) left = pow(public_key, signature, p) right = int(h, 16) return left == right # 生成素数 def generate_prime(): prime = 0 while True: prime = random.randint(1000, 10000) if is_prime(prime): break return prime # 判断是否是素数 def is_prime(n): if n <= 1: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True # 主程序 if __name__ == '__main__': # 生成素数p和本原根g p = generate_prime() g = random.randint(2, p-2) print('p =', p) print('g =', g) # Alice和Bob分别生成私钥和公钥 a = random.randint(2, p-2) b = random.randint(2, p-2) A = pow(g, a, p) B = pow(g, b, p) # Alice和Bob运行Diffie-Hellman密码协商协议生成共享密钥K K = diffie_hellman(p, g, a, b) print('K =', K) # Alice将自己的公钥发送给Bob print('Alice -> Bob: A =', A) # 连接Bob的计算机 host = '192.168.1.101' port = 12345 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) # Bob使用Alice的公钥生成对称密钥K1 B = s.recv(1024) B = int(B.decode()) K1 = pow(B, a, p) print('K1 =', K1) # Alice将秘密信息M加密为C1,并使用MD5算法生成哈希值H1 M = 'Hello, Bob!' key = generate_key() C1 = encrypt(key, M.encode()) H1 = hash(M.encode()) # Alice使用自己的私钥对哈希值H1进行数字签名,生成签名值S1 d = random.randint(2, p-2) private_key = d public_key = pow(g, d, p) S1 = sign(private_key, H1.encode()) # Alice将加密后的信息C1、哈希值H1和签名值S1发送给Bob data = str(C1) + '|' + str(H1) + '|' + str(S1) s.send(data.encode()) # 关闭连接 s.close() ``` Bob端代码: ```python import random import hashlib from Crypto.Cipher import DES import socket # Diffie-Hellman密码协商 def diffie_hellman(p, g, a, b): A = pow(g, a, p) B = pow(g, b, p) K = pow(A, b, p) return K # 生成一个DES加密密钥 def generate_key(): key = '' for i in range(8): key += chr(random.randint(0, 255)) return key # 加密 def encrypt(key, data): cipher = DES.new(key, DES.MODE_ECB) return cipher.encrypt(data) # 解密 def decrypt(key, data): cipher = DES.new(key, DES.MODE_ECB) return cipher.decrypt(data) # 计算MD5哈希值 def hash(data): h = hashlib.md5() h.update(data) return h.hexdigest() # 数字签名 def sign(private_key, data): h = hash(data) signature = pow(int(h, 16), private_key, p) return signature # 验证签名 def verify(public_key, signature, data): h = hash(data) left = pow(public_key, signature, p) right = int(h, 16) return left == right # 生成素数 def generate_prime(): prime = 0 while True: prime = random.randint(1000, 10000) if is_prime(prime): break return prime # 判断是否是素数 def is_prime(n): if n <= 1: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True # 主程序 if __name__ == '__main__': # 生成素数p和本原根g p = generate_prime() g = random.randint(2, p-2) print('p =', p) print('g =', g) # Alice和Bob分别生成私钥和公钥 a = random.randint(2, p-2) b = random.randint(2, p-2) A = pow(g, a, p) B = pow(g, b, p) # Bob将自己的公钥发送给Alice host = '192.168.1.100' port = 12345 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((host, port)) s.listen(1) conn, addr = s.accept() print('Connected by', addr) conn.send(str(B).encode()) # Alice使用Bob的公钥生成对称密钥K1 A = conn.recv(1024) A = int(A.decode()) K1 = pow(A, b, p) print('K1 =', K1) # Bob接收加密后的信息C1、哈希值H1和签名值S1,并进行解密和验证 data = conn.recv(1024) data = data.decode() C1, H1, S1 = data.split('|') C1 = eval(C1) H1 = eval(H1) S1 = int(S1) # Bob使用Alice的公钥验证签名值S1,并使用对称密钥K1解密C1得到M1 if verify(A, S1, H1.encode()): M1 = decrypt(generate_key(), C1).decode() print('Bob received:', M1) else: print('Signature verification failed!') # 关闭连接 conn.close() s.close() ``` 注意,这个代码只是简单的示例,还需要加入错误处理等功能。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值