一、TCP/IP的反馈
举例1:
public class ClientTest {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket socket = new Socket("10.12.152.129",10010) ;
//获取通道内的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("我给你打招呼".getBytes());
//读取服务器端的反馈数据
//获取当前客户端的所在的通道 的输入流
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
System.out.println("服务器反馈数据是:"+new String(bytes,0,len));
//释放资源
socket.close();
}
}
public class ServerTest {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(10010) ;
//侦听
Socket socket = ss.accept(); //获取客户端的套接字(Socket对象)
InputStream in = socket.getInputStream();
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = in.read(bytes);
System.out.println("数据来自于 :"+socket.getInetAddress().getHostAddress()+
",当前客户端发送的内容是:"+new String(bytes,0,len));
//服务器端要反馈(确认字符 :(syn+ack)包)
//获取通道内内的输出流
OutputStream out = socket.getOutputStream();
out.write("数据已经收到,请您那边确认".getBytes());
//释放资源
ss.close();
}
}
二、TCP/IP的三次握手
举例:
/* 客户端一个文本文件(ServerTest.java),通过服务器端将这个文件进行复制到当前项目的copy.java文件中
*/
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端Socket对象
Socket socket = new Socket("10.12.152.129",8888) ;
//读这个文本文件:使用字符缓冲输入流BufferedReader
BufferedReader br = new BufferedReader(new FileReader("ServerTest.java")) ;
//封装通道内的字节输出流
BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;
//读一行,给通道内包装的字符输出流中写入内容
String line = null ;
while((line=br.readLine())!=null){
//写一行到当前通道内中
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
br.close();
socket.close();
}
}
/* 通过服务器端将这个文件进行复制到当前项目的copy.java文件中
*/
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(8888) ;
Socket socket = ss.accept();
//封装通道内的基本字节输入流
BufferedReader br =
new BufferedReader(new InputStreamReader(socket.getInputStream())) ;
//输出一个文件:Copy.java:当前项目下
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));
//一次读取一行
String line = null ;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭资源
bw.close();
ss.close();
}
}
三、反射:
- 什么是反射?
反射就是获取一个类的字节码文件,然后加载该类的所有的成员
成员变量所在类---->Field
成员方法所在类---->Method
构造方法所在类—>Constructor
给成员变量赋值通过Field,调用成员方法Method,通过构造器创建的对象… - 获取一个类的字节码文件 (三种)
/ * Class类:
* public static Class<?> forName(String className):参数为当前类的全限定名称
* throws ClassNotFoundException
*/
public class RelectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//获取一个类的字节码文件对象
//1)Object类的getClass()
Person p = new Person() ;
Class c1 = p.getClass();
System.out.println(c1);//class 包名.类名
//Integer-->java.lang.Integer
//Class
//public String getName()
System.out.println(c1.getName());//获取当前Person类的全限定名称 com.qf.reflect_01.Person
System.out.println("-------------------------");
//2)任意Java类型的class属性
Class c2 = Person.class ;
System.out.println(c2);
System.out.println(c2.getName());
System.out.println(c1==c2);
System.out.println("-------------------------");
//3)Class的静态功能
Class c3 = Class.forName("com.qf.reflect_01.Person") ;
System.out.println(c3);//class com.qf.reflect_01.Person
}
}
举例:
public class Person {
public String name ;//默认的修饰符
private int age ;//私有的成员变量
String address ; //默认的修饰符
public Person(){} //公共的构造方法
private Person(String name,int age){
this.name = name ;
this.age = age ;
}
//默认的修饰
Person(String name,int age,String address){
this.name = name ;
this.age = age;
this.address = address ;
}
//成员方法
public String show(){
return "show Person";
}
private String function(int number){
return "hello,JavaEE"+number ;
}
String method(){
return "mysql" ;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
- 通过反射获取一个类的构造器并且创建当前类对象呢
* 之前的写法:
* Person perons = new Person() ;
*/
public class Reflect_getCon {
public static void main(String[] args) throws Exception {
//1)获取指定的类的字节码文件对象: com.qf.reflect_01.Person的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//2)通过字节码文件对象获取构造器(Constructor)
//public Constructor<?>[] getConstructors() throws SecurityException
//获取类的所有公共的构造方法
// Constructor[] constructors = clazz.getConstructors();
//public Constructor<?>[] getDeclaredConstructors():可获取当前类中的所有构造方法(包括私有以及默认)
/*Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor con:constructors){
System.out.println(con);
*//**
* public com.qf.reflect_01.Person() :
*
*
* com.qf.reflect_01.Person(java.lang.String,int,java.lang.String)
* private com.qf.reflect_01.Person(java.lang.String,int)
* public com.qf.reflect_01.Person()
*//*
}*/
//通过字节码文件对象获取单个构造方法:公共的
//参数为:可变参数 ...(类似于数组:参数可以有很多个)
//如果存在参数:必须参数类型的Class String ---->java.lang.String
//Person(String name,Integer i)---->参数:java.lang.String, java.lang.Integer
//无参的构造方法:不需要传参
//public Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor con = clazz.getConstructor() ;
//获取了构造器之后:通过构造器创建当前类的实例
// public T newInstance(Object... initargs):参数是给构造方法中赋值的实际参数
Object obj = con.newInstance();
System.out.println(obj);
System.out.println("--------------------");
//之前写法
Person p = new Person() ;
System.out.println(p);
// Person p1 = new Person("高圆圆",20) ;
}
}
- 通过反射获取指定的构造方法(非公共),并创建该类实例
/* 私有的构造方法不能直接new的
*/
public class Reflect_getCon2 {
public static void main(String[] args) throws Exception {
//获取Person类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person");
//获取指定的构造方法:Constructor
//private Person(String name,int age)
//获取指定的构造方法(包括私有),参数为当前参数类型的字节码文件对象
// public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor con = clazz.getDeclaredConstructor(String.class,int.class) ;
//Constructor:构造器 Method:成员方法,Field:成员变量
//公共的基类:AccessibleObject
//public void setAccessible(boolean flag):取消Java语言访问检查 (参数为true)
con.setAccessible(true);
//创建当前类的实例
// Object obj = con.newInstance("高圆圆",41) ;
// System.out.println(obj);//Person的toString方法
// //Person{name='高圆圆', age=41, address='null'}
System.out.println("----------------------------");
// Person p = new Person("高圆圆",41) ;//已经私有化
}
}
举例:
/* 访问Person类的默认修饰符的构造方法,并且创建当前类实例
* 类似于 Person p = new Person("高圆圆",41,""西安) ;
*/
public class Refelect_getCon3 {
public static void main(String[] args) throws Exception {
//获取当期类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//获取构造器Constructor
Constructor con = clazz.getDeclaredConstructor(String.class,int.class,String.class) ;
//构造方法:默认修饰符
//取消Java语言访问检查
con.setAccessible(true);
//创建该类实例
Object obj = con.newInstance("高圆圆",41,"鄠邑区") ;
System.out.println(obj);
}
}
- 通过反射方式获取成员变量Field,并给其进行赋值!
举例:
/* 之前的写法:
* //通过无参构造方法创建UI小
* Person person = new Person() ;
* person.setName("高圆圆") ;
* person.setAge(41) ;
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//1)获取指定的类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//方式1:通过无参构造器创建实例
//2)通过反射获取单个公共的构造方法,无参
/* Constructor constructor = clazz.getConstructor();
//System.out.println(constructor);
//3)通过构造器创建当前类实例
Object obj = constructor.newInstance();
System.out.println(obj);*/
//方式2:直接创建当前类实例
//Class类的功能:直接通过当前类的字节码文件对象创建当前类对象
//public T newInstance()
Object obj = clazz.newInstance();
System.out.println(obj);
//public Field[] getFields():获取当前类或者指定接口中的所有的公共的字段
//public Field[] getDeclaredFields():获取当前类中所有的字段(公共的,受保护的,私有的,默认的)
// Field[] fields = clazz.getFields();
/* Field[] fields =clazz.getDeclaredFields() ;
for(Field field:fields){
System.out.println(field);
//公共的字段(成员变量)
//public java.lang.String com.qf.reflect_01.Person.name
*//**
* public java.lang.String com.qf.reflect_01.Person.name
* private int com.qf.reflect_01.Person.age
* java.lang.String com.qf.reflect_01.Person.address
*//*
}*/
//获取指定的单个的字段(成员变量):公共字段
//name:公共的字段
//public Field getField(String name):参数名称为"成员变量名称"
Field nameField = clazz.getField("name");
//给当前Field所代表的的指定的字段name来进行赋值
// public void set(Object obj,Object value)
//将指定的值绑定在当前类的实例上
nameField.set(obj,"高圆圆");
//age:私有的属性
//address:默认修饰符
//在设置值之前,需要取消Java语言访问检查
System.out.println(obj);
System.out.println("---------------------");
//获取age所在的Field对象,为其赋值
//Field getDeclaredField(String name):获取指定的字段Field
Field ageField = clazz.getDeclaredField("age");
//取消Java语言访问检查
//私有属性
ageField.setAccessible(true);
//赋值
ageField.set(obj,41);
System.out.println(obj);
System.out.println("----------------------------");
Field addressField = clazz.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"西安市");
System.out.println(obj);
}
}
举例:
public class Student {
public void love(){
System.out.println("爱学习,爱Java");
}
}
public class Worker {
public void love(){
System.out.println("爱生活,爱敲代码...");
}
}
class.properties:
className=com.qf.reflect_04.Worker
methodName=love
/* 通过反射方式来调用Person类中的成员方法(非静态的)
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//获取Person类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person");
//获取当前类的所有的公共的成员方法:有自己的,还有继承的
//public Method[] getMethods()
//public Method[] getDeclaredMethods():获取类或者接口中的指定的成员方法(公共,默认,私有,受保护)
/* Method[] methods = clazz.getDeclaredMethods() ;
// Method[] methods = clazz.getMethods();
for(Method method :methods){
System.out.println(method);
}*/
//之前的写法:
//无参构造方法创建对象:
//Person p = new Person() ;
// p.show() ;
Constructor con = clazz.getConstructor();
//创建Person类的实例
Object obj = con.newInstance();
//通过反射获取成员方法所代表的的Method对象
//获取公共的成员方法
//参数1:方法名
//参数2:当前该方法的形式参数类型的Class
//public Method getMethod(String name ,Class<?>... parameterTypes)
Method showMethod = clazz.getMethod("show");
//要执行showMethod方法: show()
//Method
//参数1:当前类的实例
//参数2:给方法形式参数传递的实际参数
//返回值:就是调用当前方法本身的时候,如果方法是没有具体返回值,那么直接单独调用
//如果有返回值类型,那么就使用Object来结束即可!
//public Object invoke(Object obj, Object... args):
Object returnObj = showMethod.invoke(obj);
System.out.println(returnObj);
System.out.println("----------------------");
//获取function方法并调用
//Method getDeclaredMethod(String name,Class...parameterNames)
//获取指定的Method
Method functionMethod = clazz.getDeclaredMethod("function", int.class);
//取消Java语言访问检查
functionMethod.setAccessible(true);
Object retunrObj2 = functionMethod.invoke(obj, 27);
System.out.println(retunrObj2);
System.out.println("----------------------");
Method methodM = clazz.getDeclaredMethod("method") ;
methodM.setAccessible(true );
Object returnObj3 = methodM.invoke(obj);
System.out.println(returnObj3);
/* Person p = new Person() ;
System.out.println(p.show());*/
//通过反射调用function方法以及method 方法
}
}
反射的应用1:
举例:
/* 面试题
* 现在有一个ArrayList<String>,如何实现给里面存储Integer类型呢?
*
* 可以,通过反射方式操作:-----获取Class---->Method--->invoke(当前类实例,方法实际参数)
*/
public class Test {
public static void main(String[] args) throws Exception {
//创建一个ArrayList<String>
ArrayList<String> array = new ArrayList<String>() ;
array.add("hello") ;
array.add("world") ;
array.add("javaee") ;
System.out.println(array);
System.out.println("--------------------");
// array.add(100) ;
//通过反射方式调用add方法
//Object的getClass()获取字节码文件对象
Class clazz = array.getClass() ;
//clazz创建当前类实例
Object obj = clazz.newInstance();//通过反射创建
//获取Method对象:方法名 add
Method addMethod = clazz.getMethod("add", Object.class);
//调用方法
addMethod.invoke(obj,"mysql") ;
addMethod.invoke(obj,100) ;
addMethod.invoke(obj,50) ;
System.out.println(obj);
}
}
反射的应用2:
举例:
/* Class.forName("全限定名称"):参数为字符串:被经常用在配置文件中
*/
public class Test2 {
public static void main(String[] args) throws IOException, ClassNotFoundException,
IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//创建一个学生类
Student s = new Student() ;
s.love();
//代码不断变化
//工人类
Worker worker = new Worker() ;
worker.love();
//Java设计开发原则:
//开闭原则: 对现有代码的修改关闭,在现有代码基础进行扩展!
System.out.println("-----------------------------------");
//提供了一个扩展:在src下(类路径下)配置文件class.properties
//读取配置文件获取里面keyvalue属性列表,将它载入到Properties属性集合类中
InputStream inputStream = Test2.class.getClassLoader().
getResourceAsStream("class.properties");
//创建属性集合列表
Properties prop = new Properties() ;
prop.load(inputStream);
System.out.println(prop);
//通过key获取value
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//反射获取当前className里面的类的字节码文件对象
Class clazz = Class.forName(className) ;
// System.out.println(clazz);
//直接当前类实例
Object obj = clazz.newInstance();
//反射获取Method对象
Method method = clazz.getMethod(methodName);
method.invoke(obj) ;
}
}
四:mySql
- 什么是数据库?
存储数据的仓库! - 特点:
永久存储
可以支持一些事务
(数据库的事务----将整个业务操作看成一个整体:转账(要么一起成功,要么一起失败!))
执行效率高(通过sql语句)
之前存储方式:
1)临时变量 存储在内存中,方法结束 局部变量就消失了
2)数组 存储同一种类型元素,但是长度固定的!
3)StringBuffer: 字符串缓冲区 :里面存储的可变的字符序列
4)集合 存储任意类型元素,必须引用类型
取元素: 遍历 (单例集合:Iterator)
增强for循环
存储大量大数据,效率太低
5)IO流:也能存储数据
太耗时(读写过程)
3. 常见的数据库:
关系型数据库:
oracle: 针对JavaEE支持的(java平台),收费 (大型公司:金融行业:银行)
中国银行: 现在技术----SpringCloud
mysql:开源的而且免费(针对中小型公司使用居多)
相同的数据库引擎:MariaDB
SqlServer:针对net平台更兼容一些(收费的)
NoSQL:非关系数据库
key-value
代表:redis---->分布式缓存:可以缓存用户:User
缓存相关商品数据/缓存一些经常改变的数据
MangoDb
- Mysql:
必须安装mysql软件----一台计算机如果按照了mysql软件(mysql服务器)
安装版:5.5
1)安装软件
2)配置信息
a) 勾选path—勾选上:自动给配置mysql的path环境配置
b)选择编码集: utf8(最好使用这个格式)
如果gbk 在dos中使用mysql客户端的时候,中文的就会出现乱码
用户名:root:管理员用户
密码:root/自己定义(不要太简单),后期可能没有权限访问–
只能通过mysql的权限命令重写设置密码
登录
thougtWorks(外企:思特沃克)
华为:deeplin(深度Linux系统)
—配置:Mac本
Mac本:按照idea
maven工具
Linxu系统
使用进入dos控制台进行登录(黑窗口去使用)
C:\Users\zhangyang>mysql -uroot -p
Enter password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.5.40 MySQL Community Server (GPL)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
- DDL语句:
操作数据库
1). 查询当前服务器软件中的所有的数据库
show databases;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |-- mysql服务器相关的配置
| mysql |-- 存储很多相关的用户表user(权限用户)
| performance_schema |-- 跟mysql性能优化相关的表信息
| test |-- 测试数据库
+--------------------+
2). 创建新的数据库
create database 数据库名称;
create database if not exists 数据库名称;
mysql> create database if not exists EE_2104;
Query OK, 1 row affected (0.01 sec)
3). 查看创建的数据库的默认字符集
show create database 数据库名称;
mysql> show create database ee_2104;
+----------+------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------+
| ee_2104 | CREATE DATABASE `ee_2104` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+------------------------------------------------------------------+
1 row in set (0.00 sec)
4). 修改数据库的默认字符集
alter database 数据库名称 DEFAULT(可以省略) CHARACTER SET 字符集;
mysql> alter database ee_2104 character set gbk;
Query OK, 1 row affected (0.00 sec)
mysql> show create database ee_2104;
+----------+-----------------------------------------------------------------+
| Database | Create Database |
+----------+-----------------------------------------------------------------+
| ee_2104 | CREATE DATABASE `ee_2104` /*!40100 DEFAULT CHARACTER SET gbk */ |
+----------+-----------------------------------------------------------------+
5). 删除数据库
drop database 数据库名称;
drop database if exists 数据库名称;
mysql> drop database if exists ee_2104;
Query OK, 0 rows affected (0.00 sec)
6). 切换数据库(数据库本身就是一个文件夹,进入到某个文件夹中)
use 数据库名称;
mysql> use ee_2104;
Database changed
7). DDL语句:来操作表
mysql> show tables; 查询当前指定数据库中的所有表
Empty set (0.01 sec)
8). 创建表的语法:
create table 表名(
字段名称1 字段类型1,
字段名称2 字段类型2,
字段名称3 字段类型3,
....
字段名称n 字段类型n
);
9). mysql常见的字段类型
int:整数类型(推荐):默认11位
当给定的值,它获取到当前整数的实际长度(自动获取)
age int,----age = 50
int(位数):不推荐
int(4) ---age = 5 0005
varchar(指定长度):就是java类的String 字符串类型:推荐使用’’,也可以双引号 ,也可以不带引号
举例
name varchar(20):name字段最大能支持20个字符
date:日期 : 仅仅只是表示日期,没有时间
datetime:日期+当前时间
timestap:时间戳 (就当前被访问/操作具体:当前系统时间)
double(5,3):小数类型,可以5位数据,小数点后3位…
double 小数类型:100 —>100.0
mysql> create table student(
-> sid int,
-> name varchar(10),
-> age int,
-> address varchar(10),
-> gender varchar(5),
-> birthday date
-> );
Query OK, 0 rows affected (0.02 sec)
10). 查询表的结构:desc 表名;
mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| sid | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| address | varchar(10) | YES | | NULL | |
| gender | varchar(5) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
6 rows in set (0.03 sec)
11). 修改表:
给表中添加一列(添加一个字段)
alter table 表名 add 字段名称 字段类型;
mysql> alter table student add hobit varchar(20);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| sid | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| address | varchar(10) | YES | | NULL | |
| gender | varchar(5) | YES | | NULL | |
| birthday | date | YES | | NULL | |
| hobit | varchar(20) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
12). 修改表的字段名称
alter table 表名 change 以前的列名称 新的列名称 以前的字段类型;
mysql> alter table student change gender sex varchar(5);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| sid | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| address | varchar(10) | YES | | NULL | |
| sex | varchar(5) | YES | | NULL | |
| birthday | date | YES | | NULL | |
| hobit | varchar(20) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
7 rows in set (0.02 sec)
13). 修改表的字段类型
alter table 表名 modify 字段名称 更改后的字段类型;
mysql> alter table student modify sex varchar(3) ;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| sid | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| address | varchar(10) | YES | | NULL | |
| sex | varchar(3) | YES | | NULL | |
| birthday | date | YES | | NULL | |
| hobit | varchar(20) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
7 rows in set (0.02 sec)
14). 修改的表的名称
alter table 以前表名 rename to 新表名;
mysql> alter table student rename to stu;
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+-------------------+
| Tables_in_ee_2104 |
+-------------------+
| stu |
+-------------------+
1 row in set (0.02 sec)
15). 创建表的时候复制一张相同的表
create table 新表名 like 存在的表名;
mysql> create table teacher like stu;
Query OK, 0 rows affected (0.02 sec)
mysql> show tables;
+-------------------+
| Tables_in_ee_2104 |
+-------------------+
| stu |
| teacher |
+-------------------+
2 rows in set (0.00 sec)
mysql> desc teacher;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| sid | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| address | varchar(10) | YES | | NULL | |
| sex | varchar(3) | YES | | NULL | |
| birthday | date | YES | | NULL | |
| hobit | varchar(20) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
7 rows in set (0.01 sec)
16). 删除表
drop table 表名;
drop table if exists 表名;
mysql> drop table teacher;
Query OK, 0 rows affected (0.02 sec)
五:案例:聊天室
聊天室涉及的功能:
1)注册用户(登录)
2)公聊
3)私聊
4)上下线提醒
5)发送文件…
…
客户端工程和服务器端工程
通过TCP方式:
客户端不断发送数据,服务器端不断的使用数据,并且
服务器端不断的反馈数据到客户端,客户端不断的读取数据!
问题1:
客户端 :发消息和读消息都在主线程中
服务器端:读消息和反馈(回复)消息也是在线程中
思考:是将读消息放在线程中还是写消息放在子线程中?
问题2:问题1可能会导致----互相阻塞现象
假设:
客户端将一个100M图片文件将这个文件内容读取完毕,通过通道内的 输出流写给服务器端
服务器端将图片读出来复制在指定xxx.jpg文件中
字节流的方式读— -1是作为读取完毕的条件, 客户端并不知道文件是否读完!
互相等待:
客户端等待服务器端反馈,文件复制完毕
而服务器端等待客户端 通知他(文件已经复制完了)
客户端:
public class ChatRoomClient {
public static void main(String[] args) {
//创建客户端的Socket对象
Socket socket = null ;
try {
socket = new Socket("10.12.152.129",6666) ;
//获取当前客户端所在的通道内的输入和输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//开启读取服务器转发的消息的子线程
ClientThread ct = new ClientThread(in) ;
ct.start();
while(true){
//不断的去录入数据,将数据写过去
System.out.println("请您输入消息:");
String clientMsg = sc.nextLine() ;
//自定义结束条件 :发送一个图片文件:100m
//约定的消息格式:
// 接收者:消息内容:发送者
out.write(clientMsg.getBytes());
//不断的去读取服务器端反馈的消息
/* byte[] bytes = new byte[1024] ;
int len = in.read(bytes);
String reveiveFk = new String(bytes,0,len) ;
System.out.println(reveiveFk);*/
// 思考:是将读消息放在线程中还是写消息放在子线程中?
//将读消息放在子线程中,子线程不能录入消息的!
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端子线程
/* 客户端读取消息(服务器转发消息)的子线程
*/
public class ClientThread extends Thread {
private InputStream in;
public ClientThread(InputStream in){
this.in = in ;
}
@Override
public void run() {
try{
//不断读取 服务器转发的消息
while(true){
byte[] bytes = new byte[1024] ;
int len = in.read(bytes);
String reveiveFk = new String(bytes,0,len) ;
System.out.println(reveiveFk);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
服务器端:
/* 服务器端的主线程中
*/
public class ChatRoomServer {
public static void main(String[] args) {
//创建服务器端的Socket对象,绑定指定的端口号
try {
ServerSocket ss = new ServerSocket(6666) ;
//创建ArrayList<Socket>
ArrayList<Socket> list = new ArrayList<Socket>() ;
System.out.println("服务器正在等待连接");
//定义一个变量
int i = 1 ;
//不断的监听的多个客户端
while(true){
//监听客户端并获取客户端的socket
Socket socket = ss.accept();
System.out.println("第"+(i++)+"个客户端已经连接...");
list.add(socket) ;
//获取通道的内输入和输出流
/*
OutputStream out = socket.getOutputStream();*/
InputStream in = socket.getInputStream();
//开启一个读取消息的子线程
// ServerThread st = new ServerThread(socket) ;
ServerThread st = new ServerThread(in,list) ;
//启动线程
st.start();
}
//创建键盘录入对象
// Scanner sc = new Scanner(System.in) ;
//不断去读取客户端发送的消息
/* while(true){
//读取客户端发送的消息
//下面代码需要开子线程
byte[] bytes = new byte[1024] ;
int len = in.read(bytes);
String receiveClientMsg = new String(bytes,0,len) ;
System.out.println(receiveClientMsg);
//不断的回复消息(反馈)
//服务器不回复消息
*//* System.out.println("请回复消息:");
String serverMsg = sc.nextLine() ;
out.write(serverMsg.getBytes());*//*
}*/
} catch (IOException e) {
e.printStackTrace();
}
//服务器端不关闭
}
}
服务器类子线程:
/* 服务器读取消息的子线程
*/
public class ServerThread extends Thread {
private InputStream in ;
private ArrayList<Socket> list ;
public ServerThread(InputStream in,ArrayList<Socket> list){
this.in = in ;
this.list = list ;
}
/*private Socket socket ;
public ServerThread(Socket socket){
this.socket = socket ;
}*/
//重写run方法
@Override
public void run() {
try{
//读数据的操作
//不断读取
while(true){
byte[] bytes = new byte[1024] ;
int len = in.read(bytes);
String receiveClientMsg = new String(bytes,0,len) ;
System.out.println(receiveClientMsg);//测试
//拆分消息:"接收者:消息内容:发送者"
// 1: 消息内容:0
String[] msgStr = receiveClientMsg.split(":");
// String receiver = msgStr[0] ; String类型----> int:Integer.parsetInt(msgStr[0])
// String content = msgStr[1] ;
// String sender = msgStr[2] ;
//ArrayList<Socket> list集合对.get(角标)--->某个客户端的Socket对象
//获取接收者所在的通道内的输出流,写过去
OutputStream outputStream = list.get(Integer.parseInt(msgStr[0])).getOutputStream();
//重新组装消息
outputStream.write((msgStr[2]+"对你说 "+msgStr[1]).getBytes());
}
}catch (Exception e){
}
}
}