2018-06-15 第四十天
一、TCP
使用 Socket 对象 进行 通信 ,使用底层的TCP 协议。
面向连接的协议。
1:先建立连接。 通信的两端 都会有进行通信的Socket 对象。
2:使用Socket 对象 使用字节流进行消息的通信。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 使用 Socket 连接服务器,给服务器发送一条信息。服务器收到之后,反馈一个boolean 值。
*
*/
public class MyServer {
public static final int SERVER_PORT = 1777;
public static void main(String[] args) throws Exception{
//创建建立连接服务的 服务对象。
ServerSocket ss = new ServerSocket(SERVER_PORT);
System.out.println("等待连接的请求!");
//阻塞式方法,只有连接请求发过来之后,该方法才会返回,并生成一个与连接过来的对象进行通信的Socket。
Socket socket = ss.accept();
System.out.println("连接成功!---"+socket);
//获取客户端发送的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = br.readLine();
System.out.println("服务器收到的信息为:"+str);
//给客户端回复一个boolean 值
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeBoolean(true);
dos.flush();
//需要写到finally 中 代码
socket.close();
ss.close();
}
}
class MyClient{
public static void main(String[] args) throws Exception{
//创建连接服务器的Socket 对象
Socket socket = new Socket("127.0.0.1", MyServer.SERVER_PORT);
//给服务器发送一条信息
String str = "我可以连接你么?";
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write(str);
bw.newLine();
bw.flush();
//接收服务的反馈
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println("服务器的反馈:"+dis.readBoolean());
dis.close();
bw.close();
socket.close();
}
}
二、tcp-模拟用户登录
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
/**
* 模拟用户登录
*
* 客户端:发送一个用户名+密码给服务器。接收服务器的一个反馈。
* 服务器:接收客户端的登录请求,解析客户端的用户名和密码知否有效(需要和数据库中的用户信息比对)。
* 如果用户存在,返回 true,否则返回 false。
*
*/
public class LoginServer {
public static final int SERVER_PORT = 1777;
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(SERVER_PORT);
Socket socket = ss.accept();
System.out.println(socket);
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] buf = new byte[100];
int count = bis.read(buf);
String str = new String(buf,0,count);
String name = str.split("&")[0].split("=")[1];
String pwd = str.split("&")[1].split("=")[1];
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeBoolean(hasUser(name,pwd));
dos.flush();
socket.close();
ss.close();
}
/**
* 判断 配置文件中,是否包含指定的用户
* @param name
* @param pwd
* @return
*/
public static boolean hasUser(String name, String pwd)throws Exception{
Properties users = new Properties();
users.load(new FileInputStream("./res/users.txt"));
boolean bool = users.containsKey(name);
if(bool){//人存在,比对密码
if(users.getProperty(name).equals(pwd)){
return true;
}
return false;
}
return false;
}
}
class LoginClient{
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.51.242", LoginServer.SERVER_PORT);
String str = "name=xiaogang&pwd=123456";
byte[] buf = str.getBytes();
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(buf);
bos.flush();
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println("服务器的反馈:"+dis.readBoolean());
//只关闭socket 即可。
socket.close();
}
}
三、tcp-转换大写
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 需求:客户端给服务器发送一个字符串,可以多次发送,服务器接收到之后,将字符串的大写形式返回。
* 客户端发送一个bye,结束转换
*
*/
public class UpperCaseServer {
//收到字符串,转换为大写返回
public static final int SERVER_PORT = 1777;
public static final String BYE_STR = "bye";
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(SERVER_PORT);
//监听连接请求
Socket socket = ss.accept();
System.out.println(socket);
//得到读取输入流的字符输入流,,得到往输出流写数据的字符输出流
// br 用于读取小写信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//bw 用户回复大写
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(true){
//读取客户端发送的内容,转换大写,回复,切记要刷新
String string = br.readLine();
if(BYE_STR.equals(string)){
break;
}
bw.write(string.toUpperCase());
bw.newLine();
bw.flush();
}
socket.close();
ss.close();
}
}
class UpperCaseClient{
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.51.242", UpperCaseServer.SERVER_PORT);
//bw 用于发送给服务器信息的 字符输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//br 用于读取服务器反馈的
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//用于本地输入的
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
while(true){
System.out.println("请您输入要转换的内容:");
//接收键盘的输入
String string = input.readLine();
//将string 发送给服务器
bw.write(string);
bw.newLine();
bw.flush();
//如果输入了bye ,结束 循环
if(UpperCaseServer.BYE_STR.equals(string))
break;
//读取服务器的反馈
String response = br.readLine();
System.out.println(response);
}
socket.close();
}
}
四、tcp-上传文件
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器上传文件:
*
* 客户端:
* 1:先把文件的名字传给服务器
* 2:读取本地文件的数据,发送给服务器。
*
* 服务器:
* 1:接收文件的名字
* 2:接收文件数据,写入到本地。
*
*/
public class UploadFileServer {
public static final int PORT = 1777;
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(PORT);
Socket socket = ss.accept();
System.out.println(socket);
DataInputStream dis = new DataInputStream(socket.getInputStream());
//获得文件的名字
String fileName = dis.readUTF();
//写到本地字节输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:/server/"+fileName));
//读取客户端发送的数据
BufferedInputStream bis =new BufferedInputStream(socket.getInputStream());
byte[] buf = new byte[100];
int count = bis.read(buf);
while(count != -1){
bos.write(buf, 0, count);
count = bis.read(buf);
}
bos.flush();
bos.close();
//给客户端的反馈
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(fileName + "\t上传成功!");
dos.flush();
socket.close();
ss.close();
}
}
class UploadFileClient{
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.51.242", UploadFileServer.PORT);
File file = new File("c:/dear.jpg");
//将文件的名字发过去
String name = file.getName();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(name);
dos.flush();
//可以得到文件的字节大小,给服务器发过去。
//发送字节数据
//读取本地字节数据
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
//将读取到的字节数据发送出去
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buf = new byte[100];
//读取本地字节数据
int count = bis.read(buf);
while(count != -1){
bos.write(buf, 0, count);
//读取本地字节数据
count = bis.read(buf);
}
bos.flush();
bis.close();
//给输出流添加一个流的末尾的标识,不会影响其他的流
socket.shutdownOutput();
//接收服务器的反馈 ,文件上传成功
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println("服务器反馈:"+dis.readUTF());
socket.close();
}
}
五、tcp-并发上传
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
/**
* 服务器上传文件:
*
* 服务器:
* 1:可以同时 响应多个客户端上传文件的请求
* 2:需要满足一个客户端 多次上传同一个文件的需求。
* 客户端的IP地址 + 当前时间的时间戳(System.currentTimeMillis()) + 文件名.txt
*/
public class UploadFileServer {
public static final int PORT = 1777;
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(PORT);
ArrayList<Socket> sockets = new ArrayList<>();
try {
while(true){
Socket socket = ss.accept();
//得到一个socket 连接之后,立马启动一个线程,该线程负责 当前得到的socket 对象和 与之对应的客户端的通信。
sockets.add(socket);
System.out.println(socket);
//来了一个请求,就需要启动一个线程,该线程负责和该请求进行通信。
new SocketThread(socket).start();
}
} finally {
ss.close();
}
}
/**
* 用来和客户端的一个请求的socket 进行通信的。
*
*/
static class SocketThread extends Thread{
private Socket socket;
public SocketThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
DataInputStream dis = new DataInputStream(socket.getInputStream());
//获得文件的名字
String fileName = dis.readUTF();
//写到本地字节输出流
//TODO
String ip = socket.getInetAddress().getHostAddress();
String timeStr = Long.toString(System.currentTimeMillis());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:/server/"+ip+"_"+timeStr + "_"+ fileName));
//读取客户端发送的数据
BufferedInputStream bis =new BufferedInputStream(socket.getInputStream());
byte[] buf = new byte[10000];
int count = bis.read(buf);
while(count != -1){
bos.write(buf, 0, count);
count = bis.read(buf);
//Thread.sleep(10);
}
bos.flush();
bos.close();
//给客户端的反馈
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(fileName + "\t上传成功!");
dos.flush();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
六、断点续传
1:从服务器下载文件。
第一步:给服务器发送一个 下载文件的名字(String);
第二步:服务器从本地读取指定的文件,再通过输出流发送给客户端。
中断了。
2:需要发送2调数据:
1:想要下载的文件的名字。
2:已经下载的文件的大小。
服务器收到已经下载的字节数据的大小,从指定的位置开始读取文件下发给客户端。
---- skip(1024*1024)。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 从服务器下载文件。断点续传
*
*/
public class DownLoadFileServer {
public static final int SERVER_PORT = 1777;
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(SERVER_PORT);
Socket socket = ss.accept();
//读取文件的名字
DataInputStream dis = new DataInputStream(socket.getInputStream());
String fileName = dis.readUTF();
//读取文件的大小(已经下载的文件大小)
long size = dis.readLong();
//发送文件是否存在
File file = new File("c://server/"+fileName);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
boolean exist = file.exists();
dos.writeBoolean(exist);
if(!exist){//文件不存在,结束
socket.close();
ss.close();
return;
}
//读取本地数据,发送给客户端
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buf = new byte[1000];
//从文件指定的位置读取
bis.skip(size);
int count = bis.read(buf);
while(count!= -1){
bos.write(buf,0,count);
bos.flush();
count = bis.read(buf);
}
bis.close();
socket.close();
ss.close();
}
}
/**
* 服务器下载文件,客户端
*
*/
class DownLoadFileClient{
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.51.242" , DownLoadFileServer.SERVER_PORT);
//发送请求文件名字
File file = new File("c://dear.jpg");
String fileName = file.getName();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(fileName);
dos.flush();
//如果文件存在,发送文件大小给服务器,不存在发送0 给服务器
long size = 0;
if(file.exists()){
size = file.length();
}
dos.writeLong(size);
dos.flush();
//接收服务器的反馈,如果服务器文件不存在,则直接终止程序
DataInputStream dis = new DataInputStream(socket.getInputStream());
boolean fileExist = dis.readBoolean();
if(!fileExist){
System.out.println("请求文件不存在,下载 失败!");
socket.close();
return;
}
//接收服务器发送的数据写到本地。切记要写入指定的文件,尾部追加
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, true));
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] buf = new byte[1000];
int count = bis.read(buf);
while(count != -1){
bos.write(buf, 0, count);
bos.flush();
count = bis.read(buf);
Thread.sleep(10);
}
bos.close();
socket.close();
}
}
1:如果涉及到缓冲流,Buffered 相关的, 要及时对流进行刷新 调用flush 方法。
2:关闭流的时候,只需要关闭socket ,关闭socket 就会把socket 的inputStream 和OutputStream 同时关闭。
3:如果需要关闭socket 的inputStream 和OutputStream 先关输入输出流,再关socket。
4:如果涉及到readLine 方法。需要保证对方会发送一行数据已经行的结束标识。 newLine() 或者使用PrintWriter 要打开自动刷新功能。 的println()。
5:通过关闭socket的输入输出流 通过close 关闭 ,都会导致socket不可用。
6:通过shutDownInputStream 和 shutDownOutputStream 只会单方面的关闭某一个流,不会导致另外的一个流不可用。
八、泛型
1:概念:泛型:generic type---参数化类型。
2:泛型的有效期:编译期。
泛型是从java 源文件 编程成 class 的过程中,对泛型约束的类型进行检查。
在class 文件中。所有的泛型相关的信息都将被擦除掉。
运行期将不再进行泛型类型的检查。
3:泛型类
class MyStack<T>{
T t;
void test(T t){
}
}
4:泛型接口---泛型接口实现子类。
interface MyInterface<T>{
void test(T t);
}
//子类实现父接口,如果父接口是一个泛型接口,那么子类的也许要指定泛型,和父接口类型一致。
class MyInterfaceImpl<Integer> implements MyInterface<Integer>{
@Override
public void test(Integer t) {
}
}
5:泛型通配符(方法参数泛型不固定)
//? 泛型通配符,可以认为是所有泛型类型的父类型
//? 某种特定的类型。可以是任意类型。
static void test(ArrayList<?> list){
}
这个时候,调用该方法,list 中的元素的类型可以是任意类类型。
6:复杂的泛型方法:
声明
使用
泛型类中使用泛型方法
7:静态方法与泛型
泛型类中的静态的方法,不能直接使用类的泛型类型。因为类的泛型的类型是依赖于对象的。而静态方法是依赖于类加载。
如果想在静态方法中使用泛型类的类型,那么必须将该方法声明成泛型方法。
(静态泛型方法的泛型的类型可以和所在的类的泛型的类型相同,也可以不同)
8:泛型的上下边界
方法参数的边界控制 ?
//希望元素的类型是 Number 和 Number 的子类类型
static void test1(List<? extends Number> list){
}
//希望元素的类型是 Number 和 Number 的父类的类型
static void test2(List<? super Number> list){
}
//泛型类的边界的控制 T
class MyStack<T extends Number>
//泛型方法边界 <T extends Number>
//泛型方法的边界的控制
//只能是Number 的子类和 Number 的类型
static <T extends Number> void test1(T t){
}
例:
import java.util.ArrayList;
import java.util.List;
public class Test1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("123");
//list.add(1);
MyStack<String> stack = new MyStack<>();
test(new ArrayList<String>());
//test1("123");
test1(new ArrayList<Object>());
}
//? 泛型通配符,可以认为是所有泛型类型的父类型
static void test(ArrayList<?> list){
}
//希望元素的类型是 Number 和 Number 的子类类型
static void test1(List<? extends Number> list){
}
//希望元素的类型是 Number 和 Number 的父类的类型
static void test2(List<? super Number> list){
}
//泛型方法
//static <T> void test1(T t){
////t 只能当Object 用。
//}
}
class Student implements Comparable<Student>{
private int age;
@Override
public int compareTo(Student o) {
//Student student = (Student)o;
return age-o.age;
}
}
//容器中元素的类型只能是 Number 和 Number 的子类类型。
class MyStack<T extends Number>{
T t;
<E> void test(E t){
}
//泛型方法的边界的控制
//只能是Number 的子类和 Number 的类型
static <T extends Number> void test1(T t){
}
}
interface MyInterface<T>{
void test(T t);
}
//子类实现父接口,如果父接口是一个泛型接口,那么子类的也许要指定泛型,和父接口类型一致。
class MyInterfaceImpl<Integer> implements MyInterface<Integer>{
@Override
public void test(Integer t) {
}
}

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python新式类 new init 单例模式与作用域(四)
1 新式类与旧式类 新式类拥有经典类的全部特性之外,还有一些新的特性,比如 __init__发生变化,新增了静态方法__new__,python3目前都采用新式类,新式类是广度优先,旧式类是深度优先 #新式类 class C(object): pass #经典类 class B: pass (1)内置的object对象 1. __new__,__init__方法 这两个方法是用来创建object的子类对象,静态方法__new__()用来创建类的实例,然后再调用 __init__()来初始化实例。 2. __delattr__, __getattribute__, __setattr__方法 对象使用这些方法来处理属性的访问 3. __hash__, __repr__, __str__方法 print(someobj)会调用someobj.__str__(), 如果__str__没有定义,则会调用someobj.__repr__(), __str__()和__repr__()的区别: 默认的实现是没有任何作用的 __repr__的目标是对象信息唯一性 __str__的目标是对象信息的可读...
- 下一篇
Java集合框架源码解析之数组与链表
本系列文章会陆续对 Java 集合框架(Java Collections Framework,JDK1.8)中的几个常用容器结合源码进行介绍,帮助读者建立起对 Java 集合框架清晰而深入的理解,也算是对自己所学内容的一个总结归纳 因为数组与链表是 Java 集合框架中很多地方都涉及到的知识点,此篇文章作为开头,就先对数组与链表这两种数据结构进行介绍 数组与链表是两种差别较大的数据结构,在内存空间上的存储方式也有很大区别 数组 假设现在有6个元素存放在数组中,则数组在内存中的存储结构就如下图所示 数组是一块连续的内存空间,包含的元素按照坐标索引依次排列,可以直接通过坐标定位到每一个数据的内存地址,例如可以直接通过坐标 3 获取到 element4,省去了链表中的遍历过程,因此随机读取数据的效率较高 相对应的,由于要求数组中的元素是连续的,在添加数据或移除数据时,有可能会导致大量数据在内存中的前后移动,因此数组在添加和移除数据时效率较低 数组在使用前需要先指定其空间大小,如果我们在使用前已知待存入的数据量,自然可以直接以此进行初始化而不会浪费内存空间,但实际数据量往往是未知的,通常会因为...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS8编译安装MySQL8.0.19