Java学习笔记(二十五)——通信(cs架构)
Posted Biangbangbing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习笔记(二十五)——通信(cs架构)相关的知识,希望对你有一定的参考价值。
想要设计实现通信功能。需要掌握以下知识:
网络通信(计网),多线程。
需要实现以下功能:
- 将传输的数据(文字,数字,声音,图片,视频……)编码,转换成可以通信传输的数据。
- 实现A和B(至少是双方)的通信。
<AB实质是两个进程,可以是通过公网ip相互访问连接的两个机器运行的两个进程;可以是同一局域网下的两台机器运行的两个进程;可以是一台机器跑在本机和虚拟机的两个进程;可以是同一个机器运行的两个进程>
通信模式(功能2)
CS结构(目前只学习这一个结构,后面再补充同级的结构)
我认为这是一种有关通信的模式结构,但是查资料讲是一种软件系统的体系结构。先不管外部逻辑,先关注本身细节。
- 定义:cs代表的是client-server,客户端一般认为是发出请求的一端,而server服务器端是满足客户端请求的一端,二者可以互相通信,互发数据。
- 目前使用cs结构的典型场景:网站(浏览器),游戏,数据库,qq微信等通讯工具。
- 实现cs结构:
认识一个结构:
套接字(socket)
1.将通信双方连接在一起的一个结构,存在方式为一对儿。
2.一对包含:
ServerSocket:适用于服务器端的socket 。该结构对象创建的时候只需指明端口号,ip为运行代码的机器的ip。(ip和端口常常是固定不变的方便多个客户端进行访问)
Socket:适用于客户端的socket。该结构创建对象时候需要指明其申请访问的服务器的ip和端口,运行这个程序的进程的端口是机器自行分配的。
代码实现:
需要分别为客户端和服务器端分别写一个类,然后实现对应功能,当两个机器分别跑这个两个程序的时候就实现了进程之间通信。
- 服务器端(server):
- 创建服务器端的socket对象:serverSocket。
- 实现其连接客户端的方法:
- 为刚刚创建的对象申请空间。调用构造函数需要传递服务器的端口号。(服务器端的端口是自己决定的)
- 通过serverSocket的accept()方法,连接到申请访问该服务器的客户端。并且创建一个客户端socket并返回。
- 利用这个返回的客户端socket获取输入输出io,实现服务器端向客户端发送或者接收数据。
读写数据:
首先拿到读写io流 ,服务器端通过监听返回的客户端socket的getInputStream或者getOutputStream方法来获取。
客户端通过 获取。
InputStream:输入流,对应读方法,对应接收数据。
is.read()返回读出的数据,每次读取一个字节,读完之后的内容就没有了紧接着读取下一个字节。当彻底读完之后返回-1。
因为每次只能读出一部分,所以要循环读取,然后判断是否读空,再结束。
OutputStream:输出流,对应写方法,对应发送数据。
os.write(写入缓冲区的数据,byte类型,一次写入一个字节)。
ps:整个写入读出的过程遵循队列特点先进先出。
- 客户端(client):
- 创建客户端的socket对象。
- 实现其访问服务器端的方法:
- 为客户端socket开辟空间,用构造函数需要传入要申请访问的服务器的ip和端口port。
- 发送或接收数据。
代码:见末尾工程链接。
代码遇到的问题:
可以尝试实现一个客户端,一个服务器端交流;多个客户端,一个服务器端。交流分为单次交流或者可以持续不断的交流。
-
当在实现多个客户端对一个服务器端,只发生一次交流的时候会出现一个特殊的问题:
现在指定客户端读取数据,服务器端写数据。
server:
服务器端先与多个客户端进行连接,然后向多个客户端发送数据。
client:
每个客户端与服务器端建立连接,然后接收服务器端发送的数据。(并向其回信。)在客户端的执行main函数中循环创建多个客户端,每一个执行上面的方法。
下面让server先执行,然后其执行到accept,因为没有client请求访问,因此其检测不到进入休眠,下面开始运行client进程,请求访问,因为要读取server发送的数据,但是server还没有发送,因此进入休眠;于是server进程又开始执行,这次检测到了第一个client的访问,然后想要检测第二个client的访问,检测不到就休眠;第一个client一直在等server给他发消息,但是因为server在等下一个client的连接,没有发送数据,于是他也等着,堵着一直轮不到第二个client执行,于是双方僵持。
解决办法:将建立连接和发送数据写到一个循环内,只要建立了连接就发送数据。让第一个client执行完。然后顺利执行第二个client。
改完之后可以发现client可以读到消息了,但是第二个client并没有按照预期建立。
因为server发送完数据之后没有关闭数据流,client读取的时候就无法检测到读取完不会检测到返回-1,一直陷入while循环中,因此第一个client的方法永远无法执行完。
这时就会造成只能创建一个client的情况。但是当有多个server进程执行的时候可以做到分别接收一个client然后向其分别发送信息,client接收信息。
于是在写操作的执行完毕之后加上io流的刷新和关闭。就可以成功实现一个server,多个client交流一次。
-
紧接着我还尝试了多个client收到消息后向server回复消息的情况:
发现因为之前server写完之后关闭了io流,client想要再次向server发送数据的时候,server那边就会报Socket is closed。
应该需要多线程解决。待解决。
-
当只有一个server,一个client的时候就可以实现进行多次交流。
传输数据包装
传输的时候以字节为单位,每次传输1个字节。当想要传输int,string,图片,直线,视频……等等特殊大小的结构时,需要自行单独设计传输类来实现不同特殊数据类型的读写。
无论哪一种结构,基本思路都是:先将写入的数据转换成字节数组写进去,读出的时候,将字节数组读出转换成需要的数据类型。
需要注意的是注意读写顺序以及每个数据类型与byte转换大小关系。(等下填写具体实现方法)
-
int(4byte)
send:
将要发送的数据拆成4个byte发送。从高到低依次发送,分别右移24,16,8,0位,然后&0xff,就取到了4个字节。分别os.write(int x0)。因为只想单纯的取到这8位的数字,不考虑正负等,即没有符号位,所以用int类型保存取出的一个字节,相当于只用int的低8位。
receive:
连续取出4个字节,先取出的是高位,取出后分别左移24,16,8位,然后加起来就是之前要传输的int。
-
str(每个字符2个byte)
send:
约定第一个字节发送str的长度。后面是string转换成对应的byte数组。先发长度,再发byte数组。
receive:
先读出长度,根据长度建立一个对应大小的byte数组。然后直接用is.read(byte[])方法,将数据一次性读到byte数组里。
-
Line
send:
设计Line类,包含4个整数,x1,y1,x2,y2。然后分别用传入的Line对象的get方法得到4个坐标,分别调用int的读写方法,发送信息。
receive:
用int的收信息方法收四次之后,利用构造方法创建Line对象,返回。
-
Color
send:
传入Color对象,获取其rgb值,然后调用int方法传输rgb的数字。
receive:
用int的的读数据方法,读出rgb,然后根据读出的数字构造颜色对象并返回。
-
Picture(还没尝试过,待测试)
send:
传入picture对象,通过imagebuffer将其转换成二维数组,每个像素点是一个color对象。调用传输color方法依次传输。
receive:
用color的的读数据方法,读出二维矩阵,然后根据构造方法将其转化为imagebuffer对象。
代码
GitHub - Biangbangbing/VMeeting
Java基础学习笔记二十五 MySQL
MySQL
在dos中操作mysql
连接mysql命令: mysql -uroot -p密码 ,连接OK,会出现mysql>
对数据库的操作
创建一个库
create database 库名 create database 库名 character set 编码
mysql> create database mybase; Query OK, 1 row affected (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mybase | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec)
创建带有编码的
create database mybase01 character set gbk;
mysql> create database mybase01 character set gbk; Query OK, 1 row affected (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mybase | | mybase01 | | mysql | | performance_schema | | test | +--------------------+ 6 rows in set (0.00 sec)
查看编码:
mysql> show create database mybase01; +----------+------------------------------------------------------------------+ | Database | Create Database | +----------+------------------------------------------------------------------+ | mybase01 | CREATE DATABASE `mybase01` /*!40100 DEFAULT CHARACTER SET gbk */ | +----------+------------------------------------------------------------------+ 1 row in set (0.00 sec)
查看数据库
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mybase | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec)
删除一个库
drop database 库名
mysql> drop database mybase; Query OK, 0 rows affected (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec)
使用库 use 库名
mysql> use mybase Database changed
查看当前正在操作的库 select database();
mysql> select database(); +------------+ | database() | +------------+ | mybase | +------------+ 1 row in set (0.00 sec)
对数据库表的操作
创建一张表
创建数据表的格式 create table 表名( 列名1 数据类型 约束, 列名2 数据类型 约束, 列名3 数据类型 约束 );
/* 创建用户表,用户编号,姓名,用户的地址 将编号列,设置为主键约束,保证列的数据唯一性,非空性 primary key AUTO_INCREMENT 让主键列数据,实现自动增长 */ CREATE TABLE users ( uid INT PRIMARY KEY AUTO_INCREMENT , uname VARCHAR(20), uaddress VARCHAR(200) );
mysql> CREATE TABLE users ( -> uid INT PRIMARY KEY AUTO_INCREMENT , -> uname VARCHAR(20), -> uaddress VARCHAR(200) -> ); Query OK, 0 rows affected (0.02 sec)
查看数据库表 show tables;
mysql> show tables; +------------------+ | Tables_in_mybase | +------------------+ | users | +------------------+ 1 row in set (0.00 sec)
查看表的结构 desc 表名
mysql> desc users; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | uid | int(11) | NO | PRI | NULL | auto_increment | | uname | varchar(20) | YES | | NULL | | | uaddress | varchar(200) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)
删除一张表 drop table 表名
mysql> drop table users; Query OK, 0 rows affected (0.00 sec) mysql> show tables; Empty set (0.00 sec)
修改表
添加一列 alter table 表名 add 字段名 类型(长度) [约束]
mysql> alter table users add tel int; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0
mysql> desc users ; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | uid | int(11) | NO | PRI | NULL | auto_increment | | uname | varchar(20) | YES | | NULL | | | uaddress | varchar(200) | YES | | NULL | | | tel | int(11) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 4 rows in set (0.01 sec)
修改列的类型(长度、约束) alter table 表名 modify 要修改的字段名 类型(长度) [约束]
mysql> alter table users modify tel varchar(50); Query OK, 0 rows affected (0.27 sec) Records: 0 Duplicates: 0 Warnings: 0
修改列的列名 alter table 表名 change 旧列名 新列名 数据类型 约束
mysql> alter table users change tel newtel double; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0
mysql> desc users ; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | uid | int(11) | NO | PRI | NULL | auto_increment | | uname | varchar(20) | YES | | NULL | | | uaddress | varchar(200) | YES | | NULL | | | newtel | double | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec)
删除表的列 alter table 表名 drop 列名
mysql> alter table users drop newtel; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc users; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | uid | int(11) | NO | PRI | NULL | auto_increment | | uname | varchar(20) | YES | | NULL | | | uaddress | varchar(200) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)
修改表名 rename table 表名 to 新表名
mysql> rename table users to newusers; Query OK, 0 rows affected (0.01 sec) mysql> show tables; +------------------+ | Tables_in_mybase | +------------------+ | newusers | +------------------+ 1 row in set (0.00 sec)
查看表的字符集编码 show create table newusers;
mysql> show create table newusers; +----------+-------------------------------------------------------------- -------------------------------------------------------------------------- -------------------------------------------------------+ | Table | Create Table | +----------+-------------------------------------------------------------- -------------------------------------------------------------------------- -------------------------------------------------------+ | newusers | CREATE TABLE `newusers` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `uname` varchar(20) DEFAULT NULL, `uaddress` varchar(200) DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +----------+-------------------------------------------------------------- -------------------------------------------------------------------------- -------------------------------------------------------+ 1 row in set (0.00 sec)
修改表的字符集 alter table 表名 character set 编码
mysql> alter table newusers character set gbk; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table newusers; +----------+------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------+ | Table | Create Table | +----------+------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------+ | newusers | CREATE TABLE `newusers` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `uname` varchar(20) CHARACTER SET utf8 DEFAULT NULL, `uaddress` varchar(200) CHARACTER SET utf8 DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk | +----------+------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------+ 1 row in set (0.00 sec)
对数据库表记录进行操作(修改)
插入记录
insert into 表名(列名1,列名2,列名3……) values(值1,值2,值3……) insert into 表名 values(值1,值2,值3……)
insert into 表名 (列名1,列名2,列名3) values (值1,值2,值3),(值1,值2,值3)
先创建product表,然后添加数据。
CREATE TABLE product( -- 主键列,自动增长 id INT PRIMARY KEY AUTO_INCREMENT, -- 商品名字,可变字符,非空 pname VARCHAR(100) NOT NULL, -- 商品的价格,double price DOUBLE );
mysql> INSERT INTO product (id,pname,price) VALUES (1,\'笔记本\',5555.99); ERROR 1366 (HY000): Incorrect string value: \'\\xB1\\xCA\\xBC\\xC7\\xB1\\xBE\' for column \'pname\' at row 1 mysql> INSERT INTO product (id,pname,price) VALUES (2,\'智能手机\',9999); ERROR 1366 (HY000): Incorrect string value: \'\\xD6\\xC7\\xC4\\xDC\\xCA\\xD6...\' for column \'pname\' at row 1 mysql> INSERT INTO product (id,pname,price) VALUES (1,\'computer\',5555.99); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO product (id,pname,price) VALUES (1,\'phone\',5555.99); ERROR 1062 (23000): Duplicate entry \'1\' for key \'PRIMARY\' mysql> INSERT INTO product (id,pname,price) VALUES (2,\'phone\',5555.99); Query OK, 1 row affected (0.00 sec)
插入数据中文乱码问题解决办法
乱码原因:客户端和服务器之间传递字符的编码规则不一样。
方式一:直接修改数据库安装目录里面的my.ini文件的第57行【不建议】
方式二: set names gbk;
mysql> set names gbk; Query OK, 0 rows affected (0.00 sec)
再次插入中文,可以看到,不报错了。
mysql> INSERT INTO product (id,pname,price) VALUES (3,\'笔记本\',5555.99); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO product (id,pname,price) VALUES (4,\'智能手机\',9999); Query OK, 1 row affected (0.00 sec)
添加数据格式,不考虑主键 insert into 表名 (列名) values (值)
mysql> INSERT INTO product (pname,price) VALUES(\'洗衣机\',800); Query OK, 1 row affected (0.00 sec)
添加数据格式,所有值全给出 insert into 表名 values (全列值)
mysql> INSERT INTO product VALUES (6,\'微波炉\',300.25); Query OK, 1 row affected (0.00 sec)
添加数据格式,批量写入 insert into 表名 (列名1,列名2,列名3) values (值1,值2,值3),(值1,值2,值3)
mysql> INSERT INTO product (pname,price) VALUES -> (\'智能机器人\',25999.22), -> (\'彩色电视\',1250.36), -> (\'沙发\',5899.02); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0
修改表记录
先看看表中的所有数据:
mysql> select * from product; +----+------------+----------+ | id | pname | price | +----+------------+----------+ | 1 | computer | <以上是关于Java学习笔记(二十五)——通信(cs架构)的主要内容,如果未能解决你的问题,请参考以下文章