//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。。
尊重作者 转载请注明出处52mud.com