linux kernel 2.4.5 ipv4 socket层的一点解释
1.新建socket
函数原形:
static int inet_create(struct socket *sock, int protocol)
在net/ipv4/af_inet.c中
详细解释
static int inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct proto *prot;
sock->state = SS_UNCONNECTED; /* 设置状态为未连接 */
sk = sk_alloc(PF_INET, GFP_KERNEL, 1); /* 申请sock所需的内存 */
/* net/core/sock.c */
if (sk == NULL)
goto do_oom;
switch (sock->type) {
case SOCK_STREAM: /* TCP协议 */
if (protocol && protocol != IPPROTO_TCP)
goto free_and_noproto;
protocol = IPPROTO_TCP;
prot = &tcp_prot; /* tcp_prot定义在net/ipv4/tcp_ipv4.c */
sock->ops = &inet_stream_ops; /* 针对STREAM的socket操作 */
break;
case SOCK_SEQPACKET: /* 不支持 */
goto free_and_badtype;
case SOCK_DGRAM: /* UDP协议 */
if (protocol && protocol != IPPROTO_UDP)
goto free_and_noproto;
protocol = IPPROTO_UDP;
sk->no_check = UDP_CSUM_DEFAULT;
prot=&udp_prot; /* udp_prot定义在net/ipv4/udp.c */
sock->ops = &inet_dgram_ops; /* 针对DGRAM的socket操作 */
break;
case SOCK_RAW: /* RAW */
if (!capable(CAP_NET_RAW)) /* 判断是否有权利建立SOCK_RAW */
goto free_and_badperm;
if (!protocol) /* protocol不能为0 */
goto free_and_noproto;
prot = &raw_prot; /* raw_prot定义在net/ipv4/raw.c */
sk->reuse = 1; /* 允许地址重用 */
sk->num = protocol;
sock->ops = &inet_dgram_ops; /* RAW的一些特性和DGRAM相同 */
if (protocol == IPPROTO_RAW)
sk->protinfo.af_inet.hdrincl = 1;
/* 允许自己定制ip头 */
break;
default:
goto free_and_badtype;
}
if (ipv4_config.no_pmtu_disc)
sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
else
sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT;
sk->protinfo.af_inet.id = 0;
sock_init_data(sock,sk); /* 初始化一些数据 */
/* net/core/sock.c */
sk->destruct = inet_sock_destruct; /* 当销毁socket时调用inet_sock_destruct */
sk->zapped = 0;
sk->family = PF_INET;
sk->protocol = protocol;
sk->prot = prot;
sk->backlog_rcv = prot->backlog_rcv; /* prot->backlog_rcv()见各个类型的定义 */
sk->protinfo.af_inet.ttl = sysctl_ip_default_ttl; /* 设置默认ttl */
/* 修改/proc/sys/net/ipv4/ip_default_ttl */
sk->protinfo.af_inet.mc_loop = 1;
sk->protinfo.af_inet.mc_ttl = 1;
sk->protinfo.af_inet.mc_index = 0;
sk->protinfo.af_inet.mc_list = NULL;
#ifdef INET_REFCNT_DEBUG
atomic_inc(&inet_sock_nr);
#endif
if (sk->num) {
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
sk->sport = htons(sk->num); /* 设置本地端口 */
/* Add to protocol hash chains. */
sk->prot->hash(sk);
}
if (sk->prot->init) {
int err = sk->prot->init(sk); /* 协议对socket的初始化 */
if (err != 0) {
inet_sock_release(sk);
return(err);
}
}
return(0);
free_and_badtype:
sk_free(sk); /* 释放内存 */
return –ESOCKTNOSUPPORT;
free_and_badperm:
sk_free(sk);
return –EPERM;
free_and_noproto:
sk_free(sk);
return –EPROTONOSUPPORT;
do_oom:
return –ENOBUFS;
}
在net/core/sock.c
void sock_init_data(struct socket *sock, struct sock *sk)
{
skb_queue_head_init(&sk->receive_queue); /* 初始化3条队列 接受,发送,错误*/
skb_queue_head_init(&sk->write_queue);
skb_queue_head_init(&sk->error_queue);
init_timer(&sk->timer); /* 初始化timer */
sk->allocation = GFP_KERNEL;
sk->rcvbuf = sysctl_rmem_default;
sk->sndbuf = sysctl_wmem_default;
sk->state = TCP_CLOSE;
sk->zapped = 1;
sk->socket = sock;
if(sock)
{
sk->type = sock->type;
sk->sleep = &sock->wait;
sock->sk = sk;
} else
sk->sleep = NULL;
sk->dst_lock = RW_LOCK_UNLOCKED;
sk->callback_lock = RW_LOCK_UNLOCKED;
/* sock_def_wakeup(),sock_def_readable(),
sock_def_write_space(),sock_def_error_report(),
sock_def_destruct() 在net/core/sock.c */
sk->state_change = sock_def_wakeup;
sk->data_ready = sock_def_readable;
sk->write_space = sock_def_write_space;
sk->error_report = sock_def_error_report;
sk->destruct = sock_def_destruct;
sk->peercred.pid = 0;
sk->peercred.uid = –1;
sk->peercred.gid = –1;
sk->rcvlowat = 1;
sk->rcvtimeo = MAX_SCHEDULE_TIMEOUT; /* 设置接受,发送超时 */
sk->sndtimeo = MAX_SCHEDULE_TIMEOUT;
atomic_set(&sk->refcnt, 1);
}
1.1 SOCK_STREAM的初始化
在net/ipv4/tcp_ipv4.c
static int tcp_v4_init_sock(struct sock *sk)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
skb_queue_head_init(&tp->out_of_order_queue);
tcp_init_xmit_timers(sk);
tcp_prequeue_init(tp);
tp->rto = TCP_TIMEOUT_INIT;
tp->mdev = TCP_TIMEOUT_INIT;
/* So many TCP implementations out there (incorrectly) count the
* initial SYN frame in their delayed-ACK and congestion control
* algorithms that we must have the following bandaid to talk
* efficiently to them. -DaveM
*/
tp->snd_cwnd = 2;
/* See draft-stevens-tcpca-spec-01 for discussion of the
* initialization of these values.
*/
tp->snd_ssthresh = 0x7fffffff; /* Infinity */
tp->snd_cwnd_clamp = ~0;
tp->mss_cache = 536;
tp->reordering = sysctl_tcp_reordering;
sk->state = TCP_CLOSE;
sk->write_space = tcp_write_space; /* tcp_write_space() 在net/ipv4/tcp.c */
sk->use_write_queue = 1;
sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific;
/* ipv4_specific 在net/ipv4/tcp_ipv4.c */
sk->sndbuf = sysctl_tcp_wmem[1]; /* 设置发送和接收缓冲区大小 */
sk->rcvbuf = sysctl_tcp_rmem[1]; /* sysctl_tcp_* 在net/ipv4/tcp.c */
atomic_inc(&tcp_sockets_allocated); /* tcp_sockets_allocated是当前TCP socket的数量 */
return 0;
}
SOCK_DGRAM无初始化
1.2 SOCK_RAW初始化
在net/ipv4/raw.c
static int raw_init(struct sock *sk)
{
struct raw_opt *tp = &(sk->tp_pinfo.tp_raw4);
if (sk->num == IPPROTO_ICMP)
memset(&tp->filter, 0, sizeof(tp->filter));
return 0;
}
2.Server
2.1 bind
static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;
struct sock *sk=sock->sk;
unsigned short snum;
int chk_addr_ret;
int err;
/* If the socket has its own bind function then use it. (RAW) */
if(sk->prot->bind)
return sk->prot->bind(sk, uaddr, addr_len);
/* 只有SOCK_RAW定义了自己的bind函数 */
if (addr_len < sizeof(struct sockaddr_in))
return –EINVAL;
chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
/* inet_addr_type返回地址的类型 */
/* 在net/ipv4/fib_frontend.c */
/* Not specified by any standard per-se, however it breaks too
* many applications when removed. It is unfortunate since
* allowing applications to make a non-local bind solves
* several problems with systems using dynamic addressing.
* (ie. your servers still start up even if your ISDN link
* is temporarily down)
*/
if (sysctl_ip_nonlocal_bind == 0 &&
sk->protinfo.af_inet.freebind == 0 &&
addr->sin_addr.s_addr != INADDR_ANY &&
chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST &&
chk_addr_ret != RTN_BROADCAST)
return –EADDRNOTAVAIL;
snum = ntohs(addr->sin_port);
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
/* 检查是否有权利bind端口到1-1024 */
return –EACCES;
/* We keep a pair of addresses. rcv_saddr is the one
* used by hash lookups, and saddr is used for transmit.
*
* In the BSD API these are the same except where it
* would be illegal to use them (multicast/broadcast) in
* which case the sending device address is used.
*/
lock_sock(sk);
/* Check these errors (active socket, double bind). */
err = –EINVAL;
if ((sk->state != TCP_CLOSE) ||
(sk->num != 0))
goto out;
sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
sk->saddr = 0; /* Use device */
/* Make sure we are allowed to bind here. */
if (sk->prot->get_port(sk, snum) != 0) { /* get_port检查是否重用 */
sk->saddr = sk->rcv_saddr = 0;
err = –EADDRINUSE;
goto out;
}
if (sk->rcv_saddr)
sk->userlocks |= SOCK_BINDADDR_LOCK;
if (snum)
sk->userlocks |= SOCK_BINDPORT_LOCK;
sk->sport = htons(sk->num);
sk->daddr = 0;
sk->dport = 0;
sk_dst_reset(sk);
err = 0;
out:
release_sock(sk);
return err;
}
SOCK_STREAM和SOCK_DGRAM用默认的bind
2.1.1 SOCK_RAW的bind
在net/ipv4/raw.c
static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
int ret = –EINVAL;
int chk_addr_ret;
if (sk->state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
goto out;
chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
/* inet_addr_type返回地址的类型 */
/* 在net/ipv4/fib_frontend.c */
ret = –EADDRNOTAVAIL;
if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
goto out;
sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
/* sk->rcv_saddr 捆绑的本地地址 */
/* sk->saddr 源地址 */
if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
sk->saddr = 0; /* Use device */ /* 地址类型如为多播或是广播源地址为0 */
sk_dst_reset(sk);
ret = 0;
out: return ret;
}
2.2 listen
2.2.1 SOCK_STREAM的listen
在net/ipv4/af_inet.c
int inet_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
unsigned char old_state;
int err;
lock_sock(sk);
err = –EINVAL;
if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
goto out;
old_state = sk->state;
if (!((1<<old_state)&(TCPF_CLOSE|TCPF_LISTEN)))
goto out;
/* Really, if the socket is already in listen state
* we can only allow the backlog to be adjusted.
*/
if (old_state != TCP_LISTEN) {
err = tcp_listen_start(sk); /* 真正实现TCP协议listen */
if (err)
goto out;
}
sk->max_ack_backlog = backlog;
err = 0;
out:
release_sock(sk);
return err;
}
//tcp_listen_start在net/ipv4/tcp.h
int tcp_listen_start(struct sock *sk)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct tcp_listen_opt *lopt;
sk->max_ack_backlog = 0;
sk->ack_backlog = 0;
tp->accept_queue = tp->accept_queue_tail = NULL;
tp->syn_wait_lock = RW_LOCK_UNLOCKED;
tcp_delack_init(tp); /* tp清0 */
/* include/net/tcp.h */
lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL);
if (!lopt)
return –ENOMEM;
memset(lopt, 0, sizeof(struct tcp_listen_opt));
for (lopt->max_qlen_log = 6; ; lopt->max_qlen_log++)
if ((1<<lopt->max_qlen_log) >= sysctl_max_syn_backlog)
break;
write_lock_bh(&tp->syn_wait_lock);
tp->listen_opt = lopt;
write_unlock_bh(&tp->syn_wait_lock);
/* There is race window here: we announce ourselves listening,
* but this transition is still not validated by get_port().
* It is OK, because this socket enters to hash table only
* after validation is complete.
*/
sk->state = TCP_LISTEN;
if (sk->prot->get_port(sk, sk->num) == 0) { /* 确认地址没有重用 */
sk->sport = htons(sk->num); /* 设置源端口 */
sk_dst_reset(sk);
sk->prot->hash(sk); /* 将端口加到hash表中 */
return 0;
}
sk->state = TCP_CLOSE;
write_lock_bh(&tp->syn_wait_lock);
tp->listen_opt = NULL;
write_unlock_bh(&tp->syn_wait_lock);
kfree(lopt);
return –EADDRINUSE;
}
SOCK_DGRAM 和 SOCK_RAW 不支持listen
2.3 accept
2.3.1 SOCK_STREAM的accept
在net/ipv4/af_inet.c
int inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk1 = sock->sk;
struct sock *sk2;
int err = –EINVAL;
if((sk2 = sk1->prot->accept(sk1,flags,&err)) == NULL)
goto do_err;
lock_sock(sk2);
BUG_TRAP((1<<sk2->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE));
sock_graft(sk2, newsock); /* 将sk2转接到newsock */
/* 在include/net/sock.h */
newsock->state = SS_CONNECTED;
release_sock(sk2);
return 0;
do_err:
return err;
}
SOCK_DGRAM 和 SOCK_RAW 不支持 accept
2.3.1.1 TCP协议的accept
在net/ipv4/tcp.c
struct sock *tcp_accept(struct sock *sk, int flags, int *err)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
struct open_request *req;
struct sock *newsk;
int error;
lock_sock(sk);
/* We need to make sure that this socket is listening,
* and that it has something pending.
*/
error = –EINVAL;
if (sk->state != TCP_LISTEN) /* 检查socket是否处于listen状态 */
goto out;
/* Find already established connection */
if (!tp->accept_queue) { /* 判断accept队列是否准备好 */
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
/* 判断是否为堵塞模式 */
/* 在include/net/sock.h */
/* If this is a non blocking socket don’t sleep */
error = –EAGAIN;
if (!timeo) /* 不堵塞模式,直接返回 */
goto out;
error = wait_for_connect(sk, timeo); /* 进入空闲等待连接 */
if (error)
goto out;
}
req = tp->accept_queue;
if ((tp->accept_queue = req->dl_next) == NULL)
tp->accept_queue_tail = NULL;
newsk = req->sk;
tcp_acceptq_removed(sk); /* sk当前连接数减1 */
/*在include/net/tcp.h */
tcp_openreq_fastfree(req); /* 释放内存 */
/*在include/net/tcp.h */
BUG_TRAP(newsk->state != TCP_SYN_RECV);
release_sock(sk);
return newsk;
out:
release_sock(sk);
*err = error;
return NULL;
}
/* 只有当socket为堵塞模式,该函数才会被调用 */
/* 在net/ipv4/tcp.c */
static int wait_for_connect(struct sock * sk, long timeo)
{
DECLARE_WAITQUEUE(wait, current);
int err;
/*
* True wake-one mechanism for incoming connections: only
* one process gets woken up, not the ‘whole herd’.
* Since we do not ‘race & poll’ for established sockets
* anymore, the common case will execute the loop only once.
*
* Subtle issue: "add_wait_queue_exclusive()" will be added
* after any current non-exclusive waiters, and we know that
* it will always _stay_ after any new non-exclusive waiters
* because all non-exclusive waiters are added at the
* beginning of the wait-queue. As such, it’s ok to "drop"
* our exclusiveness temporarily when we get woken up without
* having to remove and re-insert us on the wait queue.
*/
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
current->state = TASK_INTERRUPTIBLE;
release_sock(sk);
if (sk->tp_pinfo.af_tcp.accept_queue == NULL)
timeo = schedule_timeout(timeo); /* 休眠timeo时长 */
lock_sock(sk);
err = 0;
if (sk->tp_pinfo.af_tcp.accept_queue) /* accept队列可用 */
/* 也就是有连接进入 */
break;
err = –EINVAL;
if (sk->state != TCP_LISTEN)
break;
err = sock_intr_errno(timeo);
if (signal_pending(current))
break;
err = –EAGAIN;
if (!timeo)
break;
}
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
return err;
}
3.Client
3.1 connect
3.1.1 SOCK_STREAM的connect
在net/ipv4/af_inet.c
int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
int addr_len, int flags)
{
struct sock *sk=sock->sk;
int err;
long timeo;
lock_sock(sk);
if (uaddr->sa_family == AF_UNSPEC) {
err = sk->prot->disconnect(sk, flags); /* 关闭连接 */
sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
goto out;
}
switch (sock->state) {
default:
err = –EINVAL;
goto out;
case SS_CONNECTED:
err = –EISCONN;
goto out;
case SS_CONNECTING:
err = –EALREADY;
/* Fall out of switch with err, set for this state */
break;
case SS_UNCONNECTED:
err = –EISCONN;
if (sk->state != TCP_CLOSE)
goto out;
err = –EAGAIN;
if (sk->num == 0) {
if (sk->prot->get_port(sk, 0) != 0) /* 是否重用 */
goto out;
sk->sport = htons(sk->num);
}
err = sk->prot->connect(sk, uaddr, addr_len); /* 调用协议的connect */
if (err < 0)
goto out;
sock->state = SS_CONNECTING; /* socket状态设置成连接中 */
/* Just entered SS_CONNECTING state; the only
* difference is that return value in non-blocking
* case is EINPROGRESS, rather than EALREADY.
*/
err = –EINPROGRESS;
break;
}
timeo = sock_sndtimeo(sk, flags&O_NONBLOCK); /* 是否为堵塞模式 */
/* 在include/net/sock.h */
if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { /* 连接为完成 */
/* Error code is set above */
if (!timeo || !inet_wait_for_connect(sk, timeo))
/* 非堵塞模式立即返回 */
/* 堵塞模式调用inet_wait_for_connect() */
goto out;
err = sock_intr_errno(timeo);
if (signal_pending(current))
goto out;
}
/* Connection was closed by RST, timeout, ICMP error
* or another process disconnected us.
*/
if (sk->state == TCP_CLOSE)
goto sock_error;
/* sk->err may be not zero now, if RECVERR was ordered by user
* and error was received after socket entered established state.
* Hence, it is handled normally after connect() return successfully.
*/
sock->state = SS_CONNECTED; /* 设置状态为已连接 */
err = 0;
out:
release_sock(sk);
return err;
sock_error:
err = sock_error(sk) ? : –ECONNABORTED;
sock->state = SS_UNCONNECTED;
if (sk->prot->disconnect(sk, flags))
sock->state = SS_DISCONNECTING;
goto out;
}
/* 只有当socket为堵塞模式,该函数才会被调用 */
/* 在/net/ipv4/af_inet.c */
static long inet_wait_for_connect(struct sock *sk, long timeo)
{
DECLARE_WAITQUEUE(wait, current);
__set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(sk->sleep, &wait);
/* Basic assumption: if someone sets sk->err, he _must_
* change state of the socket from TCP_SYN_*.
* Connect() does not allow to get error notifications
* without closing the socket.
*/
while ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
release_sock(sk);
timeo = schedule_timeout(timeo); /* 进入休眠 */
lock_sock(sk);
if (signal_pending(current) || !timeo)
break;
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return timeo;
}
摘自: http://www.infosecurity.org.cn/article/hacker/tutor/12424.html
清明诗词
古人有描写清明扫墓的诗:
三月里来是清明,桃红柳绿百草青;
别家坟上飘白纸,我家坟上冷清清。
南北山头多墓田,清明祭扫各纷然;
纸灰飞作白蝴蝶,泪血染成红杜鹃。
古墓花影白杨树,尽是生死离别处!
清明节
清明节
【清明节起源】
寒食节
【25个民族过清明节】
【清明节由来】
【清明节习俗】
apache日志分析命令
日志格式:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\""
实时查看:
tail -f access_log | awk -F"[" ‘{print $2}’ | awk -F"]" ‘{print $1}’ | uniq -c
结果显示每秒的访问量,如果只关心某个接口,添加grep就行了
按天统计:
cat access_log.20090401 | php -R ‘preg_match("/(GET|POST){1} (\/[^? ]+)/",$argn, $matches);$arr[$matches[2]]++; $sum++;’ -E ‘foreach($arr as $key=>$val) echo $val . "\t" . $val/$sum*100 ."%\t". $key ."\n"; echo "total\t$sum";’ |sort -nr
统计查询字符串里面的某个参数:
cat access_log.20090401 | php -R ‘preg_match("/(GET|POST) [^\"]*entry=([^& ]*)[&
]?/",$argn,$matches);echo $matches[2]."\n";’ | sort -n | uniq -c | sort -rn
匹配2009-08-27~29 三天的日志,用户名以 _[0-9a-z]{5} 结尾:
grep space /data2/ssologs/login/200908/*2[7-9] | grep "| LoginFlow |" | grep "| 2 |" | grep credentail | awk -F "|" –posix ‘$6 ~ / [^_]+_[0-9a-z]{5} $/’
注意: 这里的 {} 属于posix的正则,需要选项 –posix
关于js的加载顺序
写JavaScript时,加载顺序是非常关心的,下面的一个脚本演示了加载的顺序:
演示地址:
http://phpor.net/projects/js/test_async.js.php?m=a
http://phpor.net/projects/js/test_async.js.php?m=b
http://phpor.net/projects/js/test_async.js.php?m=c
http://phpor.net/projects/js/test_async.js.php?m=d
http://phpor.net/projects/js/test_async.js.php?m=e
—————————test_async.js.php
<?php
if(isset($_GET[‘js2’])){
sleep(1);
echo "alert(‘outer2 js’);";
exit();
}
if(isset($_GET[‘js’])){
//sleep(1);
echo ‘document.write(\'<script src="?js2"></script>\’);’;
echo "alert(‘outer js’);";
exit();
}
if($_GET[‘m’] == ‘a’){
echo ‘<script src="?js"></script>’;
echo ‘<script> alert("inner js"); </script>’;
} else if($_GET[‘m’] == ‘b’){
echo ‘<script>document.write(\'<script src="?js"><\/script>\’);alert("inner js");</script>’;
} else if($_GET[‘m’] == ‘c’){
echo ‘<script>document.write(\'<script src="?js"><\/script>\’);</script><script>alert("inner js");</script>’;
} else {
?>
<script>
var loadScript = function (id, scriptSource, charset) {
var head = document.getElementsByTagName(‘head’)[0];
var oldScript = document.getElementById(id);
if (oldScript) {
head.removeChild(oldScript);
}
var newScript = document.createElement(‘script’);
if (charset) {
newScript.charset = charset;
} else {
newScript.charset = ‘gb2312’;
}
newScript.id = id;
newScript.type = ‘text/javascript’;
newScript.src = scriptSource;
head.appendChild(newScript);
};
</script>
<?php
if($_GET[‘m’] == ‘d’) {
echo ‘<script >loadScript("scriptid","?js");</script>’;
echo ‘<script> alert("inner js"); </script>’;
} else if($_GET[‘m’] == ‘e’){
echo ‘<script >loadScript("scriptid","?js");alert("inner js");</script>’;
}
}
?>
——————————————————
mysql 大小写敏感比较 binary
mysql 的条件语句中默认是大小写不敏感的,就是说 ‘a’=’A’ 结果为true;如果才能让 a !=A呢? 使用binary关键字,但是还要注意一下问题:
表结构:
mysql> desc innodb;
+———+————–+——+—–+———+——-+
| Field | Type | Null | Key | Default | Extra |
+———+————–+——+—–+———+——-+
| name | varchar(100) | NO | PRI | | |
| content | mediumtext | YES | | NULL | |
+———+————–+——+—–+———+——-+
2 rows in set (0.09 sec)
表内容:
mysql> select * from innodb;
+——+———+
| name | content |
+——+———+
| c | d |
| d | d |
| e | d |
| kkk | ttttt |
+——+———+
4 rows in set (0.01 sec)
查询使用了主键索引:
mysql> desc select * from innodb where name= "C";
+—-+————-+——–+——+—————+———+———+——-+——+————-+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+——–+——+—————+———+———+——-+——+————-+
| 1 | SIMPLE | innodb | ref | PRIMARY | PRIMARY | 202 | const | 1 | Using where |
+—-+————-+——–+——+—————+———+———+——-+——+————-+
1 row in set (0.00 sec)
使用binary时,主键索引用不上了:
mysql> desc select * from innodb where binary name= "C";
+—-+————-+——–+——+—————+——+———+——+——+————-+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+——–+——+—————+——+———+——+——+————-+
| 1 | SIMPLE | innodb | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
+—-+————-+——–+——+—————+——+———+——+——+————-+
1 row in set (0.01 sec)
修改表结构,直接将列设置为
mysql> alter table innodb modify name varchar(100) BINARY NOT NULL default ” ;
Query OK, 4 rows affected (0.40 sec)
Records: 4 Duplicates: 0 Warnings: 0
显示name列是binary的了,查看一下:
mysql> show create table innodb;
+——–+———————————————————————————
| Table | Create Table
+——–+———————————————————————————
| innodb | CREATE TABLE innodb
(
name
varchar(100) character set gbk collate gbk_bin NOT NULL default ”,
content
mediumtext,
PRIMARY KEY (name
)
) ENGINE=InnoDB DEFAULT CHARSET=gbk |
+——–+———————————————————————————
1 row in set (0.01 sec)
再测试select看看是否能用上索引:
mysql> desc select * from innodb where name= "C";
+—-+————-+——-+——+—————+——+———+——+——+—————————————————–+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+——-+——+—————+——+———+——+——+—————————————————–+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables |
+—-+————-+——-+——+—————+——+———+——+——+—————————————————–+
1 row in set (0.00 sec)
很遗憾,索引还是没有用上
结论: 主键不要设置为binary的,否则索引无效,如果真的希望主键是大小写敏感的,可能有别的办法,继续探索。。。
binary的试试:
IE8新感受
听说IE8 出来了,就试个新儿,装了IE8一周了,逐渐发现了一些和原来不一样的东西。
1. 添加了开发人员工具
使用这个工具就可以调试js了,而且可以单步调试,这对IE来说,确实是一个革新,以前遇到js的问题,就打开firfox,现在不同了,IE单步调试js,一个字“爽”
2. 新标签页打开
IE7添加了标签页,但是总是要按住一个功能键才能从新的标签页打开,否则就打开新窗口;现在IE8可以直接新的标签页里打开了
3. 多进程之间的通信
IE7里面,一个窗口登录后,在新打开一个IE窗口,状态是未登录的;就是说没有进程间的通信,无意间发现IE8虽然多个窗口也是多个进程,但是一个窗口登录了,另一个窗口立马就知道了
苹果apple iphone蓝牙破解软件iBluetooth被破解
在经过数月的等待过后,来自Medevil的蓝牙破解程序iBluetooth终于可以通过Cydia上iSpazio的源进行下载。
软件目前可以进行蓝牙文件的传输,据称已经在很多平台上进行了测试,平均传输速率为70kb/s.
软件需要到Medevil.net进行注册,免费使用期7天,完全版售价为3.99欧元。
由于目前Medevil的网站由于流量过大暂时瘫痪,暂时没有办法取得软件注册,网上只有一些零星的试用报告,更大范围的使用结果还不得而知。
另外iSpazio还表示目前软件还是存在一些bug,可能会需要经常性的respring或是重启。所以大家可以稍微观望一下或是谨慎使用。
php 的时间函数
strtotime功能强大,可以支持好多语言中的时间:
如: strtotime("Yesterday"); strtotime("tomorrow"); ….