Java学习笔记(二十五)——通信(cs架构)

Posted Biangbangbing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习笔记(二十五)——通信(cs架构)相关的知识,希望对你有一定的参考价值。

想要设计实现通信功能。需要掌握以下知识:

网络通信(计网),多线程。

需要实现以下功能:

  1. 将传输的数据(文字,数字,声音,图片,视频……)编码,转换成可以通信传输的数据。
  2. 实现A和B(至少是双方)的通信。

<AB实质是两个进程,可以是通过公网ip相互访问连接的两个机器运行的两个进程;可以是同一局域网下的两台机器运行的两个进程;可以是一台机器跑在本机和虚拟机的两个进程;可以是同一个机器运行的两个进程>

通信模式(功能2)

CS结构(目前只学习这一个结构,后面再补充同级的结构)

我认为这是一种有关通信的模式结构,但是查资料讲是一种软件系统的体系结构。先不管外部逻辑,先关注本身细节。

  1. 定义:cs代表的是client-server,客户端一般认为是发出请求的一端,而server服务器端是满足客户端请求的一端,二者可以互相通信,互发数据。
  2. 目前使用cs结构的典型场景:网站(浏览器),游戏,数据库,qq微信等通讯工具。
  3. 实现cs结构:

认识一个结构:

套接字(socket)

1.将通信双方连接在一起的一个结构,存在方式为一对儿。

2.一对包含:

ServerSocket:适用于服务器端的socket 。该结构对象创建的时候只需指明端口号,ip为运行代码的机器的ip。(ip和端口常常是固定不变的方便多个客户端进行访问)

Socket:适用于客户端的socket。该结构创建对象时候需要指明其申请访问的服务器的ip和端口,运行这个程序的进程的端口是机器自行分配的。

代码实现:

需要分别为客户端和服务器端分别写一个类,然后实现对应功能,当两个机器分别跑这个两个程序的时候就实现了进程之间通信。

  • 服务器端(server):
  1. 创建服务器端的socket对象:serverSocket。
  2. 实现其连接客户端的方法:
  • 为刚刚创建的对象申请空间。调用构造函数需要传递服务器的端口号。(服务器端的端口是自己决定的)
  • 通过serverSocket的accept()方法,连接到申请访问该服务器的客户端。并且创建一个客户端socket并返回。
  • 利用这个返回的客户端socket获取输入输出io,实现服务器端向客户端发送或者接收数据。

读写数据:

首先拿到读写io流 ,服务器端通过监听返回的客户端socket的getInputStream或者getOutputStream方法来获取。

客户端通过   获取。

InputStream:输入流,对应读方法,对应接收数据。

is.read()返回读出的数据,每次读取一个字节,读完之后的内容就没有了紧接着读取下一个字节。当彻底读完之后返回-1。

因为每次只能读出一部分,所以要循环读取,然后判断是否读空,再结束。

OutputStream:输出流,对应写方法,对应发送数据。

os.write(写入缓冲区的数据,byte类型,一次写入一个字节)。

ps:整个写入读出的过程遵循队列特点先进先出。

  • 客户端(client)
  1. 创建客户端的socket对象。
  2. 实现其访问服务器端的方法:
  • 为客户端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架构)的主要内容,如果未能解决你的问题,请参考以下文章

Python学习笔记(二十五)操作文件和目录

Python学习笔记(二十五)序列化_JSON基础

学习笔记第二十五节课

Java基础学习笔记二十二 网络编程

JavaSE 学习笔记之正则表达式(二十五)

Unity3d - RPG项目学习笔记(二十五)