在qemu/kvm虚拟化方案中,虚拟机从主机的视角看是一个普通的进程。如果虚拟机实现收发报文,和物理环境有什么不同呢? a. 首先是报文传输的起点和终点不同,物理环境下,报文传输的起点和终点都是主机。虚拟化场景下,报文传输的起点和终点都是虚拟机,虚拟机可以跨主机也可以同主机。 b. 其次是报文的转发媒介不同,物理环境下,二层报文的转发发生在不同主机之间,主机网卡将二层报文发送到交换机,交换机通过mac地址学习建立mac地址到不同端口的映射,实现二层报文在局域网中的传输。相比之下,虚拟化场景中,二层报文转发可以是跨主机的两个进程,也可以是同主机的两个进程。
/* "delete" is set if the user wants to delete (ie, make nonpersistent)
an existing interface; otherwise, the user is creating a new
interface
用户态程序可以设置网卡持久化,也可以反向操作,禁用其持久化的模式
这些操作通过TUNSETPERSIST命令字完成
*/
if(delete) {
/* remove persistent status */
if(ioctl(tap_fd, TUNSETPERSIST, 0) < 0){
perror("disabling TUNSETPERSIST");
exit(1);
}
printf("Set '%s' nonpersistent\n", ifr.ifr_name);
}
else {
/* emulate behaviour prior to TUNSETGROUP */
if(owner == -1 && group == -1) {
owner = geteuid();
}
/* 设置虚拟化网卡的用户 */
if(owner != -1) {
if(ioctl(tap_fd, TUNSETOWNER, owner) < 0){
perror("TUNSETOWNER");
exit(1);
}
}
/* 设置虚拟化网卡的组 */
if(group != -1) {
if(ioctl(tap_fd, TUNSETGROUP, group) < 0){
perror("TUNSETGROUP");
exit(1);
}
}
/* 使能虚拟网卡持久化 */
if(ioctl(tap_fd, TUNSETPERSIST, 1) < 0){
perror("enabling TUNSETPERSIST");
exit(1);
}
if(brief)
printf("%s\n", ifr.ifr_name);
else {
printf("Set '%s' persistent and owned by", ifr.ifr_name);
if(owner != -1)
printf(" uid %d", owner);
if(group != -1)
printf(" gid %d", group);
printf("\n");
}
}
数据收发
一旦虚拟化网卡创建好之后,用户态程序可以通过文件描述符实现对虚拟化网卡的数据读写
char tun_name[IFNAMSIZ];
/* Connect to the device */
strcpy(tun_name, "tun77");
/* 创建或者连接一个虚拟化网卡tun77,获得对应的文件描述符 */
tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI); /* tun interface */
if(tun_fd < 0){
perror("Allocating interface");
exit(1);
}
/* 循环读文件描述符,检查内核是否发送了数据包到虚拟化网卡 */
/* Now read data coming from the kernel */
while(1) {
/* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
nread = read(tun_fd,buffer,sizeof(buffer));
if(nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}
/* Do whatever with the data */
printf("Read %d bytes from device %s\n", nread, tun_name);
}
int main(int argc, char *argv[]) {
int tun_fd;
unsigned int nread;
char tun_name[IFNAMSIZ];
char buffer[BUFSIZE];
int i;
/* 打开使用open工具创建的tun/tap设备tun77 */
/* Connect to the device */
strcpy(tun_name, "tun77");
tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI); /* tun interface */
if(tun_fd < 0){
perror("Allocating interface");
exit(1);
}
/* 读取并打印其内容 */
/* Now read data coming from the kernel */
while(1) {
/* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
nread = read(tun_fd,buffer,sizeof(buffer));
if(nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}
/* Do whatever with the data */
printf("\nRead %d bytes from device %s\n Raw data:\n", nread, tun_name);
for (i = 0; i < nread; i++) {
printf("%x", buffer[i]);
}
}
return(0);
}
项目需要当某事件触发时,执行http请求任务,失败时需要有重试机制,并根据失败次数的增加,重试间隔也相应增加,任务可能并发。
由于是耗时任务,首先考虑的就是用线程来实现,并且为了节约资源,因而选择线程池。
为了解决不定间隔的重试,选择Timer和TimerTask来完成
package threadpool;
public class ThreadPoolTest {
首先要说的是,不同版本数据库提供的系统表会有不同,你可以根据数据字典查看该版本数据库所提供的表。
select * from dict where table_name like '%SESSION%';
就可以查出一些表,然后根据这些表就可以获得会话信息
select sid,serial#,status,username,schemaname,osuser,terminal,ma
Admin类的主要方法注释:
1. 创建表
/**
* Creates a new table. Synchronous operation.
*
* @param desc table descriptor for table
* @throws IllegalArgumentException if the table name is res
public class LinkListTest {
/**
* we deal with two main missions:
*
* A.
* 1.we create two joined-List(both have no loop)
* 2.whether list1 and list2 join
* 3.print the join
事件回顾:由于需要修改同一个模板,里面包含2个不同的内容,第一个里面使用的时间差和第二个里面名称不一样,其他过滤器,内容都大同小异。希望杜绝If这样比较傻的来判断if-show or not,继续追究其源码。
var b = "{{",
a = "}}";
this.startSymbol = function(a) {