2011-12-03 | #1 |
高级会员
注册: 08年04月11日
来自: 盘丝洞
帖子: 311
声望力: 20
声望:
50
现金:29两梁山币
资产:1245两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
用LPC做SERVER
//written by super 偶的MUD编程经历之用LPC做SERVER。 最近把学的TCP/IP的网络知识运用了起来。就想着用LPC做一个SERVER玩玩。 首先,LPC支持的网络接口函数有: socket_accept() socket_acquire() socket_address() socket_bind() socket_close() socket_connect() socket_create() socket_error() socket_listen() socket_release() socket_status() socket_write() 大家都知道一个SERVER要运转起来,首先要先create()一个插口。 然后把某一知名端口通过blind()和create()出来的那个插口绑定起来。 然后把这一端口至于贞听(listen)状态。然后就通过accept()来接受客户端的 连接请求。 我们可以把上面这些过程看成是服务器的初始化。就可以集成为一个过程。 int s; int server_init() { int err; s = socket_create(STREAM,"create_callback","create_close"); if (s < 0) return 0; err = socket_bind(s,PORT_NUM); if (err!=EESUCCESS) return 0; err = socket_listen(s,"listen_callback"); if (err!=EESUCCESS) return 0; return 1; } 这就是一个有连接状态的服务器的初始化的例子了。 然后就是决定怎么来socket_accept()新的连接了。 按照TCP/IP的原理,socket_accept()的过程应该是由一个 死循环的进程来处理的。只要accept()返回的值大于0,那这个返回的值就是 一新接口的描叙符。 但是在LPC里面,它不支持用户来FOLK()进程,所以说,它就把以上那死循环 包装好了,做成一个listen的参数,也就是socket_listen()的argument 2. 然后是,如果有连接请求,就马上调用以socket_listen()的第二个参数为名字 的过程。 void listen_callback(int fd) { int new_fd = socket_accept(fd,"in_read_callback","in_write_callback"); do_next(new_fd); return; } 然后服务器和客户端就可以通过这个new_fd来进行通讯了。 如果这个时候服务器收到了客户端write()过来的消息。 就会自动调用in_read_callback()过程。 其实这个过程也是把一个死循环read()的过程封装起来了。 然后如果要通讯的话,就可以这样写: void in_read_callback(int fd,string mess) {} 这里的fd就是通讯的插口,mess就是收到的信息。 然后在这个过程里面可以用sscanf(mess,)来把mess处理成理想的格式 但是这时要注意一点。。要把传过来的mess最后面的/n/r,/n,/r,/r/n四种符号过滤掉。 要不然的话,你的程序可能会把这些东西弄错的。 然后就可以一直通讯到SERVER不想再通讯时就发送一个socket_close(fd) 但是这个命令是根据什么底层函数封装起来的偶就不太清楚了,所以客户端很难 捕捉到这个信息,除非也是用LPC做客户端。 下面附一简单程序: //created by super at 2001 #include < ansi.h > #include < socket_err.h > #include < net/socket.h > #include < net/socket_errors.h > #include < globals.h > #define PORT_NUM 777 inherit F_DBASE; int run_server(); int do_server(int s); int do_server1(int fd); int do_quit(int fd); int do_send_msg(int fd,string mess); int do_who(int fd); void create() { set("name","grin"); set("id","hehe"); seteuid(getuid()); run_server(); } int run_server() { int err,s; s = socket_create(STREAM,"create_callback","create_close"); if (s < 0) { tell_object(this_player(),s + ": socket create error"); return 1; } err = socket_bind(s,PORT_NUM); if (err!=EESUCCESS) { tell_object(this_player(),err + ": bind error."); return 1; } err = socket_listen(s,"listen_callback"); if (err!=EESUCCESS) { tell_object(this_player(),err + ": listen error."); return 1; } return 1; } void listen_callback(int fd) { int new_fd; if ( ( new_fd = socket_accept( fd, "in_read_callback", "in_write_callback" ) ) < 0 ) return; do_server1(new_fd); } void in_read_callback(int fd,string str) { string cmds,clas,yesno,whats; if (sscanf(str,"%s:::%s",clas,cmds) == 2) switch (clas) { case "demand" : switch (cmds) { case "who" : do_who(fd);break; //add some in here. default : socket_write(fd,"invaild deman d"); } break; case "command" : switch (cmds) { case "quit" : do_quit(fd);break; //add some in here. default : socket_write(fd,"invaild comma nd"); } break; case "send" : do_send_msg(fd,cmds);break; default : socket_write(fd,"invaild command.\n"); } else if (sscanf(str,"%s---%s",yesno,whats) == 2) CHANNEL_D->do_channel(this_object(),"sys",whats); else if (str!="\r" && str!="\n" && str!="\r\n" && str!="\n\r") { socket_write(fd,"501 message has wrong format.\n"); } } int do_who(int fd) { object *objs; string users; int i; objs = users(); if (socket_write(fd,"200 here is the online users list.\n") < 0) // CHANNLE_D->do_channel(this_object(),"sys","socket write error.") ; if (sizeof(objs)==0) return 0; users = objs[0]->query("name") + " ("+objs[0]->query("id") +")\n"; for (i=1;i < sizeof(objs);i++) { if (!environment(objs[i])) continue; if (!interactive(objs[i])) continue; users = users + objs[i]->query("name") + " ("+objs[i]->query("id ") +")\n"; } if (socket_write(fd,sizeof(objs)+" users:\n"+users) <0 ) // CHANNLE_D->do_channel(this_object(),"sys","socket write error.") ; return 1; } int do_quit(int fd) { if (socket_write(fd,"Good bye!") <0) // CHANNLE_D->do_channel(this_object(),"sys","socket write error."); socket_close(fd); return 1; } int do_send_msg(int fd,string mess) { string who,msg; object ob; if (sscanf(mess,"%s %s",who,msg) != 2) { if (socket_write(fd,"513 you must supply the user name and messa ge.") <0) return 1; } if (!find_player(who)) { if (socket_write(fd,"514 you must supply the user name.") <0) return 1; } if (strlen(msg)>40) { if (socket_write(fd,"515 message is too long.") <0) return 1; } ob = find_player(who); tell_object(ob,"有人从"+socket_address(fd)+"发送给您消息:\n"+ msg); socket_write(fd,"send completly.\n"); return 1; } int do_server1(int s) { int re; re = socket_write(s,"100 hello,welcome to MUDQQ server.\n"); if (re != EESUCCESS && re != EECALLBACK) ; // CHANNLE_D->do_channel(this_object(),"sys","socket write error."); return 1; } 呵呵,如果这个东东放到/adm/daemons下面的话,偶还可以把他做成一个黑客后门程序 。 偷到任何人的密码。HOHO。。。 如果命令过多的话,可以命令单独做成.c文件,然后在in_read_callback()里面来搜索 命令。 这样再做一个MUDOS都有可能了,呵呵。。。 第一次用LPC做SOCKET编程,呵呵,写得很幼稚,SORRY。。 |
|