Sep
25
比如在路由器上用lighttpd起的端口在80
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
再比如自己开了一个服务端口在9999
iptables -A INPUT -p tcp --dport 9999 -j ACCEPT
tomato默认不开多余的端口……
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
再比如自己开了一个服务端口在9999
iptables -A INPUT -p tcp --dport 9999 -j ACCEPT
tomato默认不开多余的端口……
Aug
29
百度的i贴吧没有官方的rss实现,挺郁闷的。花了点时间用PHP写了这个。
测试过,GoogleReader可以正常订阅;HTTP/HTTPS兼容。代码挺难看的。
要求:支持curl库的PHP空间。如果不支持curl,可以自己用fsockopen简单模拟一下。
测试过,GoogleReader可以正常订阅;HTTP/HTTPS兼容。代码挺难看的。
要求:支持curl库的PHP空间。如果不支持curl,可以自己用fsockopen简单模拟一下。
下载文件 (已下载 1371 次)
Jul
19
前一阵和momo讨论到他的基于UDP的某个系统的设计时遇到这样一个问题:在一个局域网中有多台机器,有个消息是通过UDP广播发出的,且每台机器有多个进程需要监听同一个UDP端口,应该怎么办?
由于所知有限,当时我给的解决方案是,使用类似observer模式来建立一个稍复杂的服务(其实就是个转发,但是UDP进程数量未知)。后来momo发现,其实只要通过setsockopt设置SO_REUSEADDR属性之后,多个程序就可以绑定同一个端口了。
虽然问题是解决了,但是SO_REUSEADDR并没有上面提到的那么简单,因为momo遇到的问题正好是UDP广播/多播。否则上述模型就不适用了。这里有一篇文章,对其有更详细的注解,虽然是摘自《UNIX网络编程》的,但是给出了例子,很值得学习。
SO_REUSEADDR例解:http://www.cppblog.com/ace/archive/2006/04/29/6446.aspx
unix网络编程 第一卷:http://wenku.baidu.com/view/99a6cc38376baf1ffc4fad6f.html
由于所知有限,当时我给的解决方案是,使用类似observer模式来建立一个稍复杂的服务(其实就是个转发,但是UDP进程数量未知)。后来momo发现,其实只要通过setsockopt设置SO_REUSEADDR属性之后,多个程序就可以绑定同一个端口了。
虽然问题是解决了,但是SO_REUSEADDR并没有上面提到的那么简单,因为momo遇到的问题正好是UDP广播/多播。否则上述模型就不适用了。这里有一篇文章,对其有更详细的注解,虽然是摘自《UNIX网络编程》的,但是给出了例子,很值得学习。
SO_REUSEADDR例解:http://www.cppblog.com/ace/archive/2006/04/29/6446.aspx
unix网络编程 第一卷:http://wenku.baidu.com/view/99a6cc38376baf1ffc4fad6f.html
Jul
8
在不是用iframe测试iframe app的时候(就是在新窗口打开iframe的url)可以在地址栏执行用这种方式(注:$是jQuery里头的函数)javascript:$('#id')[0].style.visibility='hidden'; 可以让某个元素不可见,但是再次改为visible时不会需要重新载入。IE8、FF3.5、Chrome5测试通过。
FB.login(cb, {perms:'perm1,perm2,...'}) 给cb的参数response的属性perms 【如function cb(response){ alert(response.perms); }】 包含的是所有授权的perms列表,逗号分隔;无论这次login方法请求的perms是多少个。
javascript:FB.api({ method: 'Auth.revokeAuthorization' });
来取消所有已经取得的权限,包括Basic Info、Bookmark,当刷新apps.facebook.com/xxxx的时候会要求重新认证。再未重新认证时如果在非iframe的方式测试FB.ui({method:'bookmark.add'}, cb)会出现引用
An error occurred with APP_NAME. Please try again later.
API Error Code: 200
API Error Description: Permissions error
Error Message: Permissions error
API Error Code: 200
API Error Description: Permissions error
Error Message: Permissions error
FB.login(cb, {perms:'perm1,perm2,...'}) 给cb的参数response的属性perms 【如function cb(response){ alert(response.perms); }】 包含的是所有授权的perms列表,逗号分隔;无论这次login方法请求的perms是多少个。
Jul
8
facebook的javascript sdk因为需要完成比较多的功能,因此体积比较大(50K左右)。
如果每次都完整载入,必然会导致浪费过多带宽,因此缓存是必要的;但是缓存会导致BUG fix或者function enhancement无法即时更新到客户端。二者之间的矛盾调和可以用调整缓存时间来解决,但是这种解决方案并不够好,尤其是灵活性不够,有时候lib一天更新几次,有时候十天半个月甚至更久都不更新,这种解决方案的适应性就不够了。
facebook用的解决方案是,将sdk进行拆分,变成两块,第一块是loader,约2KB,缓存时间1小时;第二块是lib,约50KB,缓存时间一个月。开发者只需要用script标签载入loader即可,由loader来载入lib。lib的路径是带有版本号的,当facebook更新了lib以后,只需要修改loader中lib的版本。由于版本号不同了,路径也不同了,因此浏览器会重新请求新版本的lib。
该思路摘自facebook的wiki:http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php
p.s. 这个是旧版的SDK。
如果每次都完整载入,必然会导致浪费过多带宽,因此缓存是必要的;但是缓存会导致BUG fix或者function enhancement无法即时更新到客户端。二者之间的矛盾调和可以用调整缓存时间来解决,但是这种解决方案并不够好,尤其是灵活性不够,有时候lib一天更新几次,有时候十天半个月甚至更久都不更新,这种解决方案的适应性就不够了。
facebook用的解决方案是,将sdk进行拆分,变成两块,第一块是loader,约2KB,缓存时间1小时;第二块是lib,约50KB,缓存时间一个月。开发者只需要用script标签载入loader即可,由loader来载入lib。lib的路径是带有版本号的,当facebook更新了lib以后,只需要修改loader中lib的版本。由于版本号不同了,路径也不同了,因此浏览器会重新请求新版本的lib。
该思路摘自facebook的wiki:http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php
p.s. 这个是旧版的SDK。
Jul
7
在初始化FB对象之前必须要有一个id=fb-root的元素, 比如可以用同步或者异步的方式初始化FB对象。
同步:在head里头加入<script src="http://connect.facebook.net/en_US/all.js">,最好在</body>标签之前加入FB.init方法,这样可以保证网页的其他模块都已经正常载入。
异步:适合在<body>标签之后加入,这样可以和网页其他元素并行载入。参见:http://developers.facebook.com/docs/reference/javascript/
如果调用FB.init时指定了xfbml:true,那么当前页面中的XFBML元素都会被转换;如果没有指定,那么可以调用FB.XFBML.parse(),或者指定一个元素FB.XFBML.parse(document.getElementById('ooxx'));
FB.login(cb, {perms: 'perm1,perm2...'})方法用于获取用户权限,会有个Popup提示用户选择 允许 或 不允许。用户选择后会执行cb函数,给一个response对象,包含用户授权的权限列表(逗号分隔)。权限列表见http://developers.facebook.com/docs/authentication/permissions。可以通过FQL在permissions查所有的权限,包括查询用户是否添加了书签(bookmarked)。
FB.Event.subscribe(EventName, cb)方法用于订阅当前页面的某些事件,比如fb:like事件可以用FB.Event.subscribe('edge.create', callbackFunc)来订阅。当事件出现时会调用回调函数cb,给出事件对应的参数。
FB.Data.query方法用于执行FQL语句。FQL语句不能有换行(可以的),不能SELECT *,WHERE子句必须是能够索引的。查询是异步的,会立即返回一个query对象。query对象有wait方法,传入一个回调函数,当执行完毕后会调用该函数,传入一个数组,数组的每一行是一个查询结果对象,对象的每个属性就是SELECT出来的东西,比如SELECT id, url from object_url WHERE url="http://www.felix021.com",回调函数可以获得rows[0].id rows[0].url。
可以在 http://developers.facebook.com/docs/reference/rest/fql.query 测试FQL语句的执行。permissions这个表看似只列出了两个字段,但是实际上PERMISSION_NAME这个字段是泛指所有可以在http://developers.facebook.com/docs/authentication/permissions页面查到的权限名称,而且还包括bookmarked、tab_added两个不是权限的名称(很诡异吧?),详见http://wiki.developers.facebook.com/index.php/Permissions_(FQL)。
FB.ui方法可以用于显示一些对话框(iFrame或者Popup)。比如FB.ui({method:'bookmark.add'}, cb)可以用于显示添加书签(FB对应的APP)的iFrame,在添加成功/失败后会调用cb函数,传参response,response.bookmarked=0或1表示失败或成功。
可以在 http://fbrell.com/examples 看到更详细的例子,直接测试js的sdk。
FB的js的SDK里面 console/index.html 是个很不错的example合集,下面附上我自己写的一些example
引用
<div id="fb-root"></div>
同步:在head里头加入<script src="http://connect.facebook.net/en_US/all.js">,最好在</body>标签之前加入FB.init方法,这样可以保证网页的其他模块都已经正常载入。
异步:适合在<body>标签之后加入,这样可以和网页其他元素并行载入。参见:http://developers.facebook.com/docs/reference/javascript/
如果调用FB.init时指定了xfbml:true,那么当前页面中的XFBML元素都会被转换;如果没有指定,那么可以调用FB.XFBML.parse(),或者指定一个元素FB.XFBML.parse(document.getElementById('ooxx'));
FB.login(cb, {perms: 'perm1,perm2...'})方法用于获取用户权限,会有个Popup提示用户选择 允许 或 不允许。用户选择后会执行cb函数,给一个response对象,包含用户授权的权限列表(逗号分隔)。权限列表见http://developers.facebook.com/docs/authentication/permissions。可以通过FQL在permissions查所有的权限,包括查询用户是否添加了书签(bookmarked)。
FB.Event.subscribe(EventName, cb)方法用于订阅当前页面的某些事件,比如fb:like事件可以用FB.Event.subscribe('edge.create', callbackFunc)来订阅。当事件出现时会调用回调函数cb,给出事件对应的参数。
FB.Data.query方法用于执行FQL语句。FQL语句
可以在 http://developers.facebook.com/docs/reference/rest/fql.query 测试FQL语句的执行。permissions这个表看似只列出了两个字段,但是实际上PERMISSION_NAME这个字段是泛指所有可以在http://developers.facebook.com/docs/authentication/permissions页面查到的权限名称,而且还包括bookmarked、tab_added两个不是权限的名称(很诡异吧?),详见http://wiki.developers.facebook.com/index.php/Permissions_(FQL)。
FB.ui方法可以用于显示一些对话框(iFrame或者Popup)。比如FB.ui({method:'bookmark.add'}, cb)可以用于显示添加书签(FB对应的APP)的iFrame,在添加成功/失败后会调用cb函数,传参response,response.bookmarked=0或1表示失败或成功。
可以在 http://fbrell.com/examples 看到更详细的例子,直接测试js的sdk。
FB的js的SDK里面 console/index.html 是个很不错的example合集,下面附上我自己写的一些example
May
14
epoll相关代码出自“man epoll”。发现在网上找相关代码还有点麻烦。
p.s. 推荐 apt-get source libevent 找找里面的 epoll.c 文件里的相关实现。
这里有另一个很详细的说明: https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/
p.s. 推荐 apt-get source libevent 找找里面的 epoll.c 文件里的相关实现。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#define SERVPORT 9527 /*服务器监听端口号 */
#define BACKLOG 10 /* 最大同时连接请求数 */
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock,F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts|O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
void do_use_fd(int client_fd)
{
const char str[] = "God bless you!\n";
if (send(client_fd, str, sizeof(str), 0) == -1)
perror("send");
close(client_fd);
}
int main()
{
int sockfd;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
printf("bind ok\n");
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("listen ok\b");
size_t sin_size = sizeof(struct sockaddr_in);
#define MAX_EVENTS 10
struct epoll_event ev, events[MAX_EVENTS];
int conn_sock, nfds, epollfd;
epollfd = epoll_create(10);
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
printf("epoll_create\n");
ev.events = EPOLLIN;
ev.data.fd = sockfd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
perror("epoll_ctl: sockfd");
exit(EXIT_FAILURE);
}
printf("epoll_ctl ok\n");
for (;;) {
printf("start epoll_wait\n");
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
}
printf("epoll_wait returns, nfds = %d\n", nfds);
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == sockfd) {
conn_sock = accept(sockfd,
(struct sockaddr *) &remote_addr, &sin_size);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
do_use_fd(events[n].data.fd);
}
}
}
}
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#define SERVPORT 9527 /*服务器监听端口号 */
#define BACKLOG 10 /* 最大同时连接请求数 */
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock,F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts|O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
void do_use_fd(int client_fd)
{
const char str[] = "God bless you!\n";
if (send(client_fd, str, sizeof(str), 0) == -1)
perror("send");
close(client_fd);
}
int main()
{
int sockfd;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
printf("bind ok\n");
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("listen ok\b");
size_t sin_size = sizeof(struct sockaddr_in);
#define MAX_EVENTS 10
struct epoll_event ev, events[MAX_EVENTS];
int conn_sock, nfds, epollfd;
epollfd = epoll_create(10);
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
printf("epoll_create\n");
ev.events = EPOLLIN;
ev.data.fd = sockfd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
perror("epoll_ctl: sockfd");
exit(EXIT_FAILURE);
}
printf("epoll_ctl ok\n");
for (;;) {
printf("start epoll_wait\n");
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
}
printf("epoll_wait returns, nfds = %d\n", nfds);
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == sockfd) {
conn_sock = accept(sockfd,
(struct sockaddr *) &remote_addr, &sin_size);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
do_use_fd(events[n].data.fd);
}
}
}
}
这里有另一个很详细的说明: https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/
Feb
9
这几天简单学习了一下jsp的使用(主要是看《jsp开发web应用系统参考书籍》系列pdf),大致做一下记录。
首先是环境,jdk是必须的,服务器我用tomcat,因为以前搞noah/oak的时候整过,熟悉些。具体的配置不赘述了,网上很多,无非是JAVA_HOME CLASSPATH CATALINA_HOME之类的环境变量。此外为了连上mysql,还要去下个jar,比如mysql-connector-java-5.0.8-bin.jar,可以在网上搜到。这个要放在tomcat/shared/lib/下面。当然,也是可以放在jsp的WEB-INF/lib下面,但是这个我没研究过,不太了解细节。
最简单地写JSP,其实和写ASP/PHP很像,把java当成一个面向过程的语言填上去就行了。比如经典的hello world:
因为这里的java和普通的*.java程序不一样,所有有些语句也得变,比如import不能直接用了,必须这么写:
格式为 <%@ page oo="xx" %> 这样的oo和xx有很多个,比如session开关就是通过这种方式控制,详情参考那些pdf。包含文件则用<%@ include file="xxxx" %>这样的格式。
在编写的过程中要获取GET/POST等请求的数据以及客户端IP等信息的时候,可以使用默认import进来的request对象,有getParameter()、getMethod()、getRequestURI()、getRemoteADDR()....等方法。相当于php的$_GET/$_POST/$_SERVER等变量的大杂烩。
要控制输出,比如HTTP Header或者具体的Cookie字段,则使用response对象的addCookie()、addHeader()等方法。
Session,则是使用session对象。但是要先<%@ page session="true" %>开启session。
此外还有一个和ASP同样性质也同名的Application对象。看起来像是抄ASP的。就是一个和服务器同生死的全局变量。
以上就是最简单的jsp开发需要的一些东西了。至少开发一个留言板什么都OK了 :)
至于Java Beans,这个是第六章,我还没看...
首先是环境,jdk是必须的,服务器我用tomcat,因为以前搞noah/oak的时候整过,熟悉些。具体的配置不赘述了,网上很多,无非是JAVA_HOME CLASSPATH CATALINA_HOME之类的环境变量。此外为了连上mysql,还要去下个jar,比如mysql-connector-java-5.0.8-bin.jar,可以在网上搜到。这个要放在tomcat/shared/lib/下面。当然,也是可以放在jsp的WEB-INF/lib下面,但是这个我没研究过,不太了解细节。
最简单地写JSP,其实和写ASP/PHP很像,把java当成一个面向过程的语言填上去就行了。比如经典的hello world:
<html>
<body>
<%
out.println("Hello, world!\n"); //在jsp里输出就用out啦,不是System.out。
%>
</body>
</html>
<body>
<%
out.println("Hello, world!\n"); //在jsp里输出就用out啦,不是System.out。
%>
</body>
</html>
因为这里的java和普通的*.java程序不一样,所有有些语句也得变,比如import不能直接用了,必须这么写:
引用
<%@ page import="java.sql.*" %>
格式为 <%@ page oo="xx" %> 这样的oo和xx有很多个,比如session开关就是通过这种方式控制,详情参考那些pdf。包含文件则用<%@ include file="xxxx" %>这样的格式。
在编写的过程中要获取GET/POST等请求的数据以及客户端IP等信息的时候,可以使用默认import进来的request对象,有getParameter()、getMethod()、getRequestURI()、getRemoteADDR()....等方法。相当于php的$_GET/$_POST/$_SERVER等变量的大杂烩。
要控制输出,比如HTTP Header或者具体的Cookie字段,则使用response对象的addCookie()、addHeader()等方法。
Session,则是使用session对象。但是要先<%@ page session="true" %>开启session。
此外还有一个和ASP同样性质也同名的Application对象。看起来像是抄ASP的。就是一个和服务器同生死的全局变量。
以上就是最简单的jsp开发需要的一些东西了。至少开发一个留言板什么都OK了 :)
至于Java Beans,这个是第六章,我还没看...