服务器源代码如下:
#include <stdarg.h> #include <errno.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <errno.h> #include <netinet/in.h> #include <sys/socket.h> #include <resolv.h> #include <arpa/inet.h> #include <stdlib.h> #include <signal.h> #include <getopt.h>
#define DEFAULTIP "127.0.0.1" #define DEFAULTPORT "80" #define DEFAULTBACK "10" #define DEFAULTDIR "/home" #define DEFAULTLOG "/tmp/das-server.log"
void prterrmsg(char *msg); #define prterrmsg(msg) { perror(msg); abort(); } void wrterrmsg(char *msg); #define wrterrmsg(msg) { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }
void prtinfomsg(char *msg); #define prtinfomsg(msg) { fputs(msg, stdout); } void wrtinfomsg(char *msg); #define wrtinfomsg(msg) { fputs(msg, logfp); fflush(logfp);}
#define MAXBUF 1024
char buffer[MAXBUF + 1]; char *host = 0; char *port = 0; char *back = 0; char *dirroot = 0; char *logdir = 0; unsigned char daemon_y_n = 0; FILE *logfp;
#define MAXPATH 150
/*---------------------------------------- *--- dir_up - 查找dirpath所指目录的上一级目录 *---------------------------------------- */ char *dir_up(char *dirpath) { static char Path[MAXPATH]; int len;
strcpy(Path, dirpath); len = strlen(Path); if (len > 1 && Path[len - 1] == '/') len--; while (Path[len - 1] != '/' && len > 1) len--; Path[len] = 0; return Path; }
/*------------------------------------------------------ *--- AllocateMemory - 分配空间并把d所指的内容复制 *------------------------------------------------------ */ void AllocateMemory(char **s, int l, char *d) { *s = malloc(l + 1); bzero(*s, l + 1); memcpy(*s, d, l); } /************关于本文档******************************************** *filename: das-server.c *purpose: 这是在Linux下用C语言写的目录访问服务器,支持目录浏览和文件下载 *wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 *date time:2007-01-26 19:32 *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 * 但请遵循GPL *Thanks to: Google.com *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! *********************************************************************/ /*------------------------------------------------------ *--- GiveResponse - 把Path所指的内容发送到client_sock去 *-------------------如果Path是一个目录,则列出目录内容 *-------------------如果Path是一个文件,则下载文件 *------------------------------------------------------ */ void GiveResponse(FILE * client_sock, char *Path) { struct dirent *dirent; struct stat info; char Filename[MAXPATH]; DIR *dir; int fd, len, ret; char *p, *realPath, *realFilename, *nport;
/* 获得实际工作目录或文件 */ len = strlen(dirroot) + strlen(Path) + 1; realPath = malloc(len + 1); bzero(realPath, len + 1); sprintf(realPath, "%s/%s", dirroot, Path);
/* 获得实际工作端口 */ len = strlen(port) + 1; nport = malloc(len + 1); bzero(nport, len + 1); sprintf(nport, ":%s", port);
/* 获得实际工作目录或文件的信息以判断是文件还是目录 */ if (stat(realPath, &info)) { fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\n<html><head><title>%d - %s</title></head>" "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">", errno, strerror(errno)); fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>请向管理员咨询为何出现如下错误提示:\n%s %s</font></body></html>", Path, strerror(errno)); goto out; } /* 处理浏览文件请求,即下载文件 */ if (S_ISREG(info.st_mode)) { fd = open(realPath, O_RDONLY); len = lseek(fd, 0, SEEK_END); p = (char *) malloc(len + 1); bzero(p, len + 1); lseek(fd, 0, SEEK_SET); ret = read(fd, p, len); close(fd); fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n", len); fwrite(p, len, 1, client_sock); free(p); } else if (S_ISDIR(info.st_mode)) { /* 处理浏览目录请求 */ dir = opendir(realPath); fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\n<html><head><title>%s</title></head>" "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">", Path); fprintf(client_sock, "<caption><font size=+3>目录 %s</font></caption>\n", Path); fprintf(client_sock, "<tr><td>名称</td><td>大小</td><td>修改时间</td></tr>\n"); if (dir == 0) { fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>%s</font></body></html>", strerror(errno)); return; } /* 读取目录里的所有内容 */ while ((dirent = readdir(dir)) != 0) { if (strcmp(Path, "/") == 0) sprintf(Filename, "/%s", dirent->d_name); else sprintf(Filename, "%s/%s", Path, dirent->d_name); fprintf(client_sock, "<tr>"); len = strlen(dirroot) + strlen(Filename) + 1; realFilename = malloc(len + 1); bzero(realFilename, len + 1); sprintf(realFilename, "%s/%s", dirroot, Filename); if (stat(realFilename, &info) == 0) { if (strcmp(dirent->d_name, "..") == 0) fprintf(client_sock, "<td><a href=\"http://%s%s%s\">(parent)</a></td>", host, atoi(port) == 80 ? "" : nport, dir_up(Path)); else fprintf(client_sock, "<td><a href=\"http://%s%s%s\">%s</a></td>", host, atoi(port) == 80 ? "" : nport, Filename, dirent->d_name); if (S_ISDIR(info.st_mode)) fprintf(client_sock, "<td>目录</td>"); else if (S_ISREG(info.st_mode)) fprintf(client_sock, "<td>%d</td>", info.st_size); else if (S_ISLNK(info.st_mode)) fprintf(client_sock, "<td>链接</td>"); else if (S_ISCHR(info.st_mode)) fprintf(client_sock, "<td>字符设备</td>"); else if (S_ISBLK(info.st_mode)) fprintf(client_sock, "<td>块设备</td>"); else if (S_ISFIFO(info.st_mode)) fprintf(client_sock, "<td>FIFO</td>"); else if (S_ISSOCK(info.st_mode)) fprintf(client_sock, "<td>Socket</td>"); else fprintf(client_sock, "<td>(未知)</td>"); fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime)); } fprintf(client_sock, "</tr>\n"); free(realFilename); } fprintf(client_sock, "</table></center></body></html>"); } else { /* 既非常规文件又非目录,禁止访问 */ fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\n<html><head><title>permission denied</title></head>" "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">"); fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>你访问的资源'%s'被禁止访问,请联系管理员解决!</font></body></html>", Path); } out: free(realPath); free(nport); }
/*------------------------------------------------------ *--- getoption - 分析取出程序的参数 *------------------------------------------------------ */ void getoption(int argc, char **argv) { int c, len; char *p = 0;
opterr = 0; while (1) { int option_index = 0; static struct option long_options[] = { {"host", 1, 0, 0}, {"port", 1, 0, 0}, {"back", 1, 0, 0}, {"dir", 1, 0, 0}, {"log", 1, 0, 0}, {"daemon", 0, 0, 0}, {0, 0, 0, 0} }; /* 本程序支持如一些参数: * --host IP地址 或者 -H IP地址 * --port 端口 或者 -P 端口 * --back 监听数量 或者 -B 监听数量 * --dir 网站根目录 或者 -D 网站根目录 * --log 日志存放路径 或者 -L 日志存放路径 * --daemon 使程序进入后台运行模式 */ c = getopt_long(argc, argv, "H:P:B:D:L", long_options, &option_index); if (c == -1 || c == '?') break;
if(optarg) len = strlen(optarg); else len = 0;
if ((!c && !(strcasecmp(long_options[option_index].name, "host"))) || c == 'H') p = host = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "port"))) || c == 'P') p = port = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "back"))) || c == 'B') p = back = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "dir"))) || c == 'D') p = dirroot = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "log"))) || c == 'L') p = logdir = malloc(len + 1); else if ((!c && !(strcasecmp (long_options[option_index].name, "daemon")))) { daemon_y_n = 1; continue; } else break; bzero(p, len + 1); memcpy(p, optarg, len); } }
int main(int argc, char **argv) { struct sockaddr_in addr; int sock_fd, addrlen;
/* 获得程序工作的参数,如 IP 、端口、监听数、网页根目录、目录存放位置等 */ getoption(argc, argv);
if (!host) { addrlen = strlen(DEFAULTIP); AllocateMemory(&host, addrlen, DEFAULTIP); } if (!port) { addrlen = strlen(DEFAULTPORT); AllocateMemory(&port, addrlen, DEFAULTPORT); } if (!back) { addrlen = strlen(DEFAULTBACK); AllocateMemory(&back, addrlen, DEFAULTBACK); } if (!dirroot) { addrlen = strlen(DEFAULTDIR); AllocateMemory(&dirroot, addrlen, DEFAULTDIR); } if (!logdir) { addrlen = strlen(DEFAULTLOG); AllocateMemory(&logdir, addrlen, DEFAULTLOG); }
printf ("host=%s port=%s back=%s dirroot=%s logdir=%s %s是后台工作模式(进程ID:%d)\n", host, port, back, dirroot, logdir, daemon_y_n?"":"不", getpid());
/* fork() 两次处于后台工作模式下 */ if (daemon_y_n) { if (fork()) exit(0); if (fork()) exit(0); close(0), close(1), close(2); logfp = fopen(logdir, "a+"); if (!logfp) exit(0); }
/* 处理子进程退出以免产生僵尸进程 */ signal(SIGCHLD, SIG_IGN);
/* 创建 socket */ if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { if (!daemon_y_n) { prterrmsg("socket()"); } else { wrterrmsg("socket()"); } }
/* 设置端口快速重用 */ addrlen = 1; setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen));
addr.sin_family = AF_INET; addr.sin_port = htons(atoi(port)); addr.sin_addr.s_addr = inet_addr(host); addrlen = sizeof(struct sockaddr_in); /* 绑定地址、端口等信息 */ if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) { if (!daemon_y_n) { prterrmsg("bind()"); } else { wrterrmsg("bind()"); } }
/* 开启临听 */ if (listen(sock_fd, atoi(back)) < 0) { if (!daemon_y_n) { prterrmsg("listen()"); } else { wrterrmsg("listen()"); } } while (1) { int len; int new_fd; addrlen = sizeof(struct sockaddr_in); /* 接受新连接请求 */ new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen); if (new_fd < 0) { if (!daemon_y_n) { prterrmsg("accept()"); } else { wrterrmsg("accept()"); } break; } bzero(buffer, MAXBUF + 1); sprintf(buffer, "连接来自于: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); if (!daemon_y_n) { prtinfomsg(buffer); } else { wrtinfomsg(buffer); } /* 产生一个子进程去处理请求,当前进程继续等待新的连接到来 */ if (!fork()) { bzero(buffer, MAXBUF + 1); if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) { FILE *ClientFP = fdopen(new_fd, "w"); if (ClientFP == NULL) { if (!daemon_y_n) { prterrmsg("fdopen()"); } else { prterrmsg("fdopen()"); } } else { char Req[MAXPATH + 1] = ""; sscanf(buffer, "GET %s HTTP", Req); bzero(buffer, MAXBUF + 1); sprintf(buffer, "请求取文件: \"%s\"\n", Req); if (!daemon_y_n) { prtinfomsg(buffer); } else { wrtinfomsg(buffer); } /* 处理用户请求 */ GiveResponse(ClientFP, Req); fclose(ClientFP); } } exit(0); } close(new_fd); } close(sock_fd); return 0; }
|
编译程序用下列命令:
gcc -Wall das-server.c -o das-server
注:das即 Dictory Access Server
以root用户启动服务程序用下列命令:
./das-server
或以普通用户启动服务程序用下列命令:
./das-server --port 7838
或
./das-server -P 7838
注:只有root用户才有权限启动1024以下的端口,所以如果想用默认的80端口就得用root来运行。
如果要想让程序在后台自动运行,即处理精灵模式下工作,在命令后面加上--daemon参数即可。
打开一个网络浏览器输入服务地址开始浏览,如下图:
下载文件如下图:
注:请不要下载较大的文件,比如文件大小超过10M的,因为程序是一次分配内存,会占用系统内存较大导致系统死掉!
大家都很熟悉HTTP协议的应用,因为每天都在网络上浏览着不少东西,也都知道是HTTP协议是相当简单的。每次用到FlashGet之类的下载软件下载网页,当用到那个“用FlashGet下载全部链接”时总觉得很神奇。
后来想想,其实要实现这些下载功能也并不难,只要按照HTTP协议发送request,然后对接收到的数据进行分析,如果页面上还有href之类的链接指向标志就可以进行深一层的下载了。HTTP协议目前用的最多的是1.1版本,要全面透彻地搞懂它就参考RFC2616文档吧。
下面是我用C语言编程写的一个http下载程序,希望对大家有些启发。源代码如下:
/******* http客户端程序 httpclient.c ************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <limits.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <ctype.h>
//////////////////////////////httpclient.c 开始///////////////////////////////////////////
/********************************************
功能:搜索字符串右边起的第一个匹配字符
********************************************/
char * Rstrchr(char * s, char x) {
int i = strlen(s);
if(!(*s)) return 0;
while(s[i-1]) if(strchr(s + (i - 1), x)) return (s + (i - 1)); else i--;
return 0;
}
/********************************************
功能:把字符串转换为全小写
********************************************/
void ToLowerCase(char * s) {
while(*s) *s=tolower(*s++);
}
/**************************************************************
功能:从字符串src中分析出网站地址和端口,并得到用户要下载的文件
***************************************************************/
void GetHost(char * src, char * web, char * file, int * port) {
char * pA;
char * pB;
memset(web, 0, sizeof(web));
memset(file, 0, sizeof(file));
*port = 0;
if(!(*src)) return;
pA = src;
if(!strncmp(pA, "http://", strlen("http://"))) pA = src+strlen("http://");
else if(!strncmp(pA, "https://", strlen("https://"))) pA = src+strlen("https://");
pB = strchr(pA, '/');
if(pB) {
memcpy(web, pA, strlen(pA) - strlen(pB));
if(pB+1) {
memcpy(file, pB + 1, strlen(pB) - 1);
file[strlen(pB) - 1] = 0;
}
}
else memcpy(web, pA, strlen(pA));
if(pB) web[strlen(pA) - strlen(pB)] = 0;
else web[strlen(pA)] = 0;
pA = strchr(web, ':');
if(pA) *port = atoi(pA + 1);
else *port = 80;
}
/*********************************************************************
*filename: httpclient.c
*purpose: HTTP协议客户端程序,可以用来下载网页
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2006-03-11 21:49:00
*Note: 任何人可以任意复制代码并运用这些代码,当然包括你的商业用途
* 但请遵循GPL
*********************************************************************/
int main(int argc, char *argv[])
{
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
int portnumber,nbytes;
char host_addr[256];
char host_file[1024];
char local_file[256];
FILE * fp;
char request[1024];
int send, totalsend;
int i;
char * pt;
if(argc!=2)
{
fprintf(stderr,"Usage:%s web-address\a\n",argv[0]);
exit(1);
}
printf("parameter.1 is: %s\n", argv[1]);
ToLowerCase(argv[1]);/*将参数转换为全小写*/
printf("lowercase parameter.1 is: %s\n", argv[1]);
GetHost(argv[1], host_addr, host_file, &portnumber);/*分析网址、端口、文件名等*/
printf("webhost:%s\n", host_addr);
printf("hostfile:%s\n", host_file);
printf("portnumber:%d\n\n", portnumber);
if((host=gethostbyname(host_addr))==NULL)/*取得主机IP地址*/
{
fprintf(stderr,"Gethostname error, %s\n", strerror(errno));
exit(1);
}
/* 客户程序开始建立 sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)/*建立SOCKET连接*/
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
server_addr.sin_addr=*((struct in_addr *)host->h_addr);
/* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)/*连接网站*/
{
fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
exit(1);
}
sprintf(request, "GET /%s HTTP/1.1\r\nAccept: */*\r\nAccept-Language: zh-cn\r\n\
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\r\n\
Host: %s:%d\r\nConnection: Close\r\n\r\n", host_file, host_addr, portnumber);
printf("%s", request);/*准备request,将要发送给主机*/
/*取得真实的文件名*/
if(host_file && *host_file) pt = Rstrchr(host_file, '/');
else pt = 0;
memset(local_file, 0, sizeof(local_file));
if(pt && *pt) {
if((pt + 1) && *(pt+1)) strcpy(local_file, pt + 1);
else memcpy(local_file, host_file, strlen(host_file) - 1);
}
else if(host_file && *host_file) strcpy(local_file, host_file);
else strcpy(local_file, "index.html");
printf("local filename to write:%s\n\n", local_file);
/*发送http请求request*/
send = 0;totalsend = 0;
nbytes=strlen(request);
while(totalsend < nbytes) {
send = write(sockfd, request + totalsend, nbytes - totalsend);
if(send==-1) {printf("send error!%s\n", strerror(errno));exit(0);}
totalsend+=send;
printf("%d bytes send OK!\n", totalsend);
}
fp = fopen(local_file, "a");
if(!fp) {
printf("create file error! %s\n", strerror(errno));
return 0;
}
printf("\nThe following is the response header:\n");
i=0;
/* 连接成功了,接收http响应,response */
while((nbytes=read(sockfd,buffer,1))==1)
{
if(i < 4) {
if(buffer[0] == '\r' || buffer[0] == '\n') i++;
else i = 0;
printf("%c", buffer[0]);/*把http头信息打印在屏幕上*/
}
else {
fwrite(buffer, 1, 1, fp);/*将http主体信息写入文件*/
i++;
if(i%1024 == 0) fflush(fp);/*每1K时存盘一次*/
}
}
fclose(fp);
/* 结束通讯 */
close(sockfd);
exit(0);
}
//////////////////////////////httpclient.c 结束///////////////////////////////////////////
优秀网站源码、编程源码下载网站大集中
1.51源码:http://www.51aspx.com/
2.源码之家:http://www.codejia.com/
3.源码网:http://www.codepub.com/
4.虾客源码:http://www.xkxz.com/
5.多多源码:http://www.morecode.net/
6.洪越源代码:http://www.softhy.net/
7.锋网源码:http://www.fwvv.net/
8.代码爱好者:http://www.codefans.com/
9.爱源码:http://www.aiyuanma.com/
10.酷源码:http://www.kyuanma.com/
11.搜源码:http://www.soucode.com/
12.拉基源码:http://www.lajicode.com/
13.源码开发网:http://www.codedn.com/
14.源码天空:http://www.codesky.net/
15.源码吧:http://www.asp88.net/
16.绿色源码:http://code888.cn/
17.9号源码中心:http://www.9code.com/
18.网馨源码:http://www.asppsa.com/
20.源码天下:http://www.pccode.net/
21.需要源码:http://www.needcode.cn/
22.华夏源码:http://www.haocpu.com/
23.天新网:http://codes.21tx.com/
24.源码网:http://www.yuanma5.com/
25.无忧源码:http://www.5uym.com/
26.中国下载站:http://www.cnz.cc/
27.资源吧:http://www.ziyuan8.com/
28.启明星源码:http://www.codewww.com/
29.我要源码:http://www.xia51.com/
30.清秋源码:http://www.asp678.com/
下列语句部分是Mssql语句,不可以在access中使用。
SQL分类:
DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE)
DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT)
DCL—数据控制语言(GRANT,REVOKE,COMMIT,ROLLBACK)
首先,简要介绍基础语句:
1、说明:创建数据库
CREATE DATABASE database-name
2、说明:删除数据库
drop database dbname
3、说明:备份sql server
--- 创建 备份数据的 device
USE master
EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'
--- 开始 备份
BACKUP DATABASE pubs TO testBack
4、说明:创建新表
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根据已有的表创建新表:
A:create table tab_new like tab_old (使用旧表创建新表)
B:create table tab_new as select col1,col2… from tab_old definition only
5、说明:删除新表drop table tabname
6、说明:增加一个列
Alter table tabname add column col type
注:列增加后将不能删除。DB2中列加上后数据类型也不能改变,唯一能改变的是增加varchar类型的长度。
7、说明:添加主键: Alter table tabname add primary key(col)
说明:删除主键: Alter table tabname drop primary key(col)
8、说明:创建索引:create [unique] index idxname on tabname(col….)
删除索引:drop index idxname
注:索引是不可更改的,想更改必须删除重新建。
9、说明:创建视图:create view viewname as select statement
删除视图:drop view viewname
10、说明:几个简单的基本的sql语句
选择:select * from table1 where 范围
插入:insert into table1(field1,field2) values(value1,value2)
删除:delete from table1 where 范围
更新:update table1 set field1=value1 where 范围
查找:select * from table1 where field1 like ’%value1%’ ---like的语法很精妙,查资料!
排序:select * from table1 order by field1,field2 [desc]
总数:select count * as totalcount from table1
求和:select sum(field1) as sumvalue from table1
平均:select avg(field1) as avgvalue from table1
最大:select max(field1) as maxvalue from table1
最小:select min(field1) as minvalue from table1
11、说明:几个高级查询运算词
A: UNION 运算符
UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随
UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。
B: EXCEPT 运算符
EXCEPT 运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。
C: INTERSECT 运算符
INTERSECT 运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL 随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。
注:使用运算词的几个查询结果行必须是一致的。
12、说明:使用外连接
A、left outer join:
左外连接(左连接):结果集几包括连接表的匹配行,也包括左连接表的所有行。
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
B:right outer join:
右外连接(右连接):结果集既包括连接表的匹配连接行,也包括右连接表的所有行。
C:full outer join:
全外连接:不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。
其次,大家来看一些不错的sql语句
1、说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用)
法一:select * into b from a where 1 <>1
法二:select top 0 * into b from a
2、说明:拷贝表(拷贝数据,源表名:a 目标表名:b) (Access可用)
insert into b(a, b, c) select d,e,f from b;
3、说明:跨数据库之间表的拷贝(具体数据使用绝对路径) (Access可用)
insert into b(a, b, c) select d,e,f from b in ‘具体数据库’ where 条件
例子:..from b in '"&Server.MapPath(".")&"\data.mdb" &"' where..
4、说明:子查询(表名1:a 表名2:b)
select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)
5、说明:显示文章、提交人和最后回复时间
select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
6、说明:外连接查询(表名1:a 表名2:b)
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
7、说明:在线视图查询(表名1:a )
select * from (SELECT a,b,c FROM a) T where t.a > 1;
8、说明:between的用法,between限制查询数据范围时包括了边界值,not between不包括
select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 数值1 and 数值2
9、说明:in 的使用方法
select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’)
10、说明:两张关联表,删除主表中已经在副表中没有的信息
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
11、说明:四表联查问题:
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
12、说明:日程安排提前五分钟提醒
SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5
13、说明:一条sql 语句搞定数据库分页
select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段
14、说明:前10条记录
select top 10 * form table1 where 范围
15、说明:选择在每一组b值相同的数据中对应的a最大的记录的所有信息(类似这样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成绩排名,等等.)
select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)
16、说明:包括所有在 TableA 中但不在 TableB和TableC 中的行并消除所有重复行而派生出一个结果表
(select a from tableA ) except (select a from tableB) except (select a from tableC)
17、说明:随机取出10条数据
select top 10 * from tablename order by newid()
18、说明:随机选择记录
select newid()
19、说明:删除重复记录
Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)
20、说明:列出数据库里所有的表名
select name from sysobjects where type='U'
21、说明:列出表里的所有的
select name from syscolumns where id=object_id('TableName')
22、说明:列示type、vender、pcs字段,以type字段排列,case可以方便地实现多重选择,类似select 中的case。
select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
显示结果:
type vender pcs
电脑 A 1
电脑 A 1
光盘 B 2
光盘 A 2
手机 B 3
手机 C 3
23、说明:初始化表table1
TRUNCATE TABLE table1
24、说明:选择从10到15的记录
select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc
随机选择数据库记录的方法(使用Randomize函数,通过SQL语句实现)
对存储在数据库中的数据来说,随机数特性能给出上面的效果,但它们可能太慢了些。你不能要求ASP“找个随机数”然后打印出来。实际上常见的解决方案是建立如下所示的循环:
Randomize
RNumber = Int(Rnd*499) +1
While Not objRec.EOF
If objRec("ID") = RNumber THEN
... 这里是执行脚本 ...
end if
objRec.MoveNext
Wend
这很容易理解。首先,你取出1到500范围之内的一个随机数(假设500就是数据库内记录的总数)。然后,你遍历每一记录来测试ID 的值、检查其是
否匹配RNumber。满足条件的话就执行由THEN 关键字开始的那一块代码。假如你的RNumber 等于495,那么要循环一遍数据库花的时间可就
长了。虽然500这个数字看起来大了些,但相比更为稳固的企业解决方案这还是个小型数据库了,后者通常在一个数据库内就包含了成千上万条记录。这时候不就
死定了?
采用SQL,你就可以很快地找出准确的记录并且打开一个只包含该记录的recordset,如下所示:
Randomize
RNumber = Int(Rnd*499) + 1
SQL = "SELECT * FROM Customers WHERE ID = " & RNumber
set objRec = ObjConn.Execute(SQL)
Response.WriteRNumber & " = " & objRec("ID") & " " & objRec("c_email")
不必写出RNumber 和ID,你只需要检查匹配情况即可。只要你对以上代码的工作满意,你自可按需操作“随机”记录。Recordset没有包含其他内容,因此你很快就能找到你需要的记录这样就大大降低了处理时间。
再谈随机数
现在你下定决心要榨干Random 函数的最后一滴油,那么你可能会一次取出多条随机记录或者想采用一定随机范围内的记录。把上面的标准Random 示例扩展一下就可以用SQL应对上面两种情况了。
为了取出几条随机选择的记录并存放在同一recordset内,你可以存储三个随机数,然后查询数据库获得匹配这些数字的记录:
SQL = "SELECT * FROM Customers WHERE ID = " & RNumber & " OR ID = " & RNumber2 & " OR ID = " & RNumber3
假如你想选出10条记录(也许是每次页面装载时的10条链接的列表),你可以用BETWEEN 或者数学等式选出第一条记录和适当数量的递增记录。这一操作可以通过好几种方式来完成,但是 SELECT 语句只显示一种可能(这里的ID 是自动生成的号码):
SQL = "SELECT * FROM Customers WHERE ID BETWEEN " & RNumber & " AND " & RNumber & "+ 9"
注意:以上代码的执行目的不是检查数据库内是否有9条并发记录。
随机读取若干条记录,测试过
Access语法:SELECT top 10 * From 表名 ORDER BY Rnd(id)
Sql server:select top n * from 表名 order by newid()
mysqlelect * From 表名 Order By rand() Limit n
Access左连接语法(最近开发要用左连接,Access帮助什么都没有,网上没有Access的SQL说明,只有自己测试, 现在记下以备后查)
语法elect table1.fd1,table1,fd2,table2.fd2 From table1 left join table2 on table1.fd1,table2.fd1 where ...
使用SQL语句 用...代替过长的字符串显示
语法:
SQL数据库:select case when len(field)>10 then left(field,10)+'...' else field end as news_name,news_id from tablename
Access数据库:SELECT iif(len(field)>2,left(field,2)+'...',field) FROM tablename;
Conn.Execute说明
Execute方法
该方法用于执行SQL语句。根据SQL语句执行后是否返回记录集,该方法的使用格式分为以下两种:
1.执行SQL查询语句时,将返回查询得到的记录集。用法为:
Set 对象变量名=连接对象.Execute("SQL 查询语言")
Execute方法调用后,会自动创建记录集对象,并将查询结果存储在该记录对象中,通过Set方法,将记录集赋给指定的对象保存,以后对象变量就代表了该记录集对象。
2.执行SQL的操作性语言时,没有记录集的返回。此时用法为:
连接对象.Execute "SQL 操作性语句" [, RecordAffected][, Option]
·RecordAffected 为可选项,此出可放置一个变量,SQL语句执行后,所生效的记录数会自动保存到该变量中。通过访问该变量,就可知道SQL语句队多少条记录进行了操作。
·Option 可选项,该参数的取值通常为adCMDText,它用于告诉ADO,应该将Execute方法之后的第一个字符解释为命令文本。通过指定该参数,可使执行更高效。
·BeginTrans、RollbackTrans、CommitTrans方法
/*****************************************************************
以下是研究 mysql 5.0 得出的结果,描述并使用标准 c 演示了使用 MySQL
C API 函数 简单操作数据库的流程;
例子程序在 VC6 windows 2000 上调试通过
*****************************************************************/
#include <windows.h>
#include <iostream>
#include <mysql.h> //文件位于 MySQL 提供的 C API 目录中
using namespace std; 中国开源社区www.ossforge.com
// linux 等系统中请加入 -lmysql
#pragma comment( lib, "libmysql.lib")
中国开源社区www.ossforge.com
/*****************************************************************/
///name : main
//function : 主测试函数
//access : private
//para :
// 1. : int argc
// : 系统参数个数
// 2. : char * argv[]
// : 参数数值
//return : 返回给 startup 函数的退出参数
//author : hzh
//date : 2006-06-24
/*****************************************************************/
int main( int argc, char * argv[] )
{
MYSQL mydata; 中国开源社区www.openforge.cn
//初始化数据结构
if(mysql_init(&mydata) == NULL)
{
std::cout<<"init mysql data stauct fail"<<endl;
return -1;
}
//连接数据库
if(argc == 1)
{
if(NULL == mysql_real_connect(&mydata,"127.0.0.1","root","mysql5",
"hzhdb",MYSQL_PORT,NULL,0))
{
std::cout<<"connect database fail"<<endl<<mysql_error(&mydata)<<endl;
return -1;
}
}else if(argc == 5)
{
if(NULL == mysql_real_connect(&mydata,argv[1],
argv[2],argv[3],argv[4],MYSQL_PORT,NULL,0))
{
std::cout<<"connect database fail"<<endl<<mysql_error(&mydata)<<endl;
return -1;
}
}
else
{
std::cout<<"run parameter error"<<endl;
return -1;
} 中国开源社区www.openforge.cn
std::string s_sql = "drop table hzhtest";
if(mysql_query(&mydata,s_sql.c_str()) != 0)
{
//删除表失败
mysql_close(&mydata);
std::cout<<"drop table fail"<<endl<<mysql_error(&mydata)<<endl;
}
中国开源社区www.ossforge.com
//创建数据表,字段 myid 设置了自增列属性
s_sql = "create table hzhtest(";
s_sql = "myid integer not null auto_increment,";
s_sql = "mytime datetime null,myname varchar(30),";
s_sql = " primary key(myid))";
if(mysql_query(&mydata,s_sql.c_str()) != 0)
{
//创建表失败
mysql_close(&mydata);
std::cout<<"create table fail"<<endl
<<mysql_error(&mydata)<<endl;
return -1;
} 中国开源社区www.openforge.cn
//向表中插入数据
for(int k = 1; k < 30; k)
{
s_sql = "insert into hzhtest(mytime,myname) values";
s_sql = "('2006-06-";
char buff[20];
memset(buff,0,sizeof(buff));
itoa(k,buff,10);
s_sql = buff;
中国开源社区www.ossforge.com
s_sql = " ";
中国开源社区www.openforge.cn
int i = k % 3;
memset(buff,0,sizeof(buff));
itoa(i,buff,10);
s_sql = buff;
s_sql = ":01:01'"; 中国开源社区www.ossforge.com
if(i == 0)
{
s_sql = ",NULL";
}
else
{
s_sql = ",'黄志辉";
s_sql = buff;
s_sql = "'";
}
s_sql = ")"; 中国开源社区www.openforge.cn
if(mysql_query(&mydata,s_sql.c_str()) != 0)
{
//执行SQL语句出错
std::cout<<"execute insert syntax fail"<<
endl<<mysql_error(&mydata)<<endl;
mysql_close(&mydata) ;
return -1;
}
}
中国开源社区www.openforge.cn
//查询数据并显示
s_sql = "select myid,mytime,myname from hzhtest";
if(mysql_query(&mydata,s_sql.c_str()) != 0)
{
//执行SQL语句出错
mysql_close(&mydata);
std::cout<<"execute sql syntax fail"<<
endl<<mysql_error(&mydata)<<endl;
return -1;
} 中国开源社区www.ossforge.com
MYSQL_RES *result = mysql_store_result(&mydata);
中国开源社区www.ossforge.com
//取得查询结果
int rowcount = mysql_num_rows(result);
//取得有效记录数
std::cout<<"exec sql: "<<s_sql.c_str()<<",row count: "<<rowcount<<endl;
中国开源社区www.openforge.cn
MYSQL_FIELD *fields = NULL;
//取得各字段名
for(int i = 0; fields = mysql_fetch_field(result); i)
{
std::cout<<fields->name<<"\t\t";
}
std::cout<<endl; 中国开源社区www.ossforge.com
//依次读取各条记录
MYSQL_ROW currrow = NULL;
while((currrow = mysql_fetch_row(result)) != NULL)
{
//读行的记录
for(int i = 0; i < mysql_num_fields(result); i)
{
std::cout<<(currrow[i] ? currrow[i] : "NULL")<<"\t";
}
std::cout<<endl;
} 中国开源社区www.openforge.cn
mysql_free_result(result) ;
mysql_close(&mydata);
system("pause"); 中国开源社区www.ossforge.com
return 1;
}
摘要:目前,数据库在各行各业中广泛应用。在众多商业数据库软件中,SQL SERVER
和ORACLE被较多的使用,因此这两个数据库软件的价格也较昂贵。本文主要介绍MySQL数据库在单线程或多线程程序环境下使用C
API访问MySQL数据库方法,并给出了相应代码和分析。该数据库属于开源数据库,具有较高的成熟度,并且对于社区版本可以免费使用,因此对于需要使用
C API访问数据库的项目开发,可降低开发成本。
关键词:MySQL;C API;多线程
中图分类号:TP311文献标识码:A文章编号:1009-3044(2007)16-30904-02
Based on C API MySQL Database Multi-threaded Access Methods
YU Cheng-gong
(Zhejiang Pharmaceutical College,Ningbo 315100,China)
Abstract:Currently,the database in all walks of life were widely
used.In many commercial database software,SQL Server and Oracle are
used more and therefore their prices are more expensive. This paper
describes the MySQL database in single-threaded or multi-threaded
programming environment using C API access to the MySQL database, and
gives the corresponding code and analysis. The database is open source
database, with a higher maturity level, and the community version can
be used for free. It satisfies the need to use the C API access to the
database of project development, and reduces development costs.
Key words:MySQL;C API;multi-threaded
1 引言
随着社会信息化的深入,数据库在社会各个领域被广泛应用。在这些数据库应用项目开发过程中,需要做两方面的决策:1.
使用何种数据库软件;2. 采用何种方式访问数据库。数据库软件的选择面比较宽,在目前众多商业数据库软件中,SQL SERVER
和ORACLE被较多的使用,当然这两个数据库软件的价格也较昂贵,本文选择可免费使用的MySQL数据库社区版本,MySQL库属于开源数据库,具有较
高的成熟度和可靠性。数据库的访问方式有很多,可以使用ODBC、DAO、ADO等方法,这些方法简单直接但是效率不高,不适合大型复杂的系统使用,例如
网络游戏的数据库系统开发需要考虑同时大量的数据库访问,因此访问的效率非常重要。基于C程序语言的高效率,使用C
API访问数据库可以提高数据库的访问效率。基于以上两点,本文将介绍基于C
API的MySQL数据库访问方法,给出在单线程和多线程程序环境下的具体代码和分析。
2 建表
为了方便说明数据库的访问,先建立一个数据库表TestTable,可以使用SQL语句创建该表,也可以使用MySQL提供的图形界面来创建。数据库表中字段如下:
该数据库表使用最常见的用户名和密码作为字段,本文将通过该表来实现不同程序环境下基于C API的数据库的访问方法。
3 单线程程序的数据库访问
单线程应用程序访问MySQL数据库相对简单,其过程包含以下几步:
(1)初始化MySQL库
(2)初始化数据库连接句柄
(3)连接数据库
(4)通过SQL语句操作数据库并处理相应数据
(5)关闭数据库连接
(6)结束MySQL库
通过这五个步骤即可实现数据库的访问,具体代码和分析如下:
//在main主函数中添加代码
//1.定义访问数据库所需变量
MYSQL * myData;
MYSQL_RES * res;
MYSQL_ROW row;
//2. 初始化MySQL库和数据库连接句柄
myData = mysql_init((MYSQL*) 0);
//3. 连接数据库,MYSQL_IP和MYSQL_PORT表示数据库的IP和端口
// MYSQL_ACCOUNT, MYSQL_PASSWORD表示数据库连接的帐号和密码
//MYSQL_DBNAME表示所要访问的数据库名
mysql_real_connect( myData, MYSQL_IP, MYSQL_ACCOUNT, MYSQL_PASSWORD, MYSQL_DBNAME, MYSQL_PORT,NULL, 0 )
//4. 通过SQL语句操作数据库并处理相应数据
//4.1新建用户名为abcdef,密码为123456的记录
mysql_query(myData, "insert into TestTable value(‘abcdef’,’ 123456’)");
//4.2显示所有记录
//查询所有记录
mysql_query(myData, "select * from TestTable");
//将查询结果保存到res中
res = mysql_store_result( myData ) ;
//逐条显示记录
Int j = 0;
while ( row = mysql_fetch_row( res ) ) {//获取一条记录
j = mysql_num_fields( res ) ;//获取每条记录的字段数
for ( k = 0 ; k < j ; k++ )
printf( “%s”, row[k] ) ;
printf( “\n”) ;
}
//释放res
mysql_free_result( res ) ;
//5. 关闭数据库连接
mysql_close( myData );
//6. 结束MySQL库
mysql_library_end();
关于代码的几点说明:
(1)定义变量中的三个数据结构为访问MySQL所需,MYSQL结构表示一个数据库连接的句柄,其中包含了数据库连接所需的参数,MYSQL_RES结构表示数据库访问中一个查询的返回结果,MYSQL_ROW结构表示返回结构中的一条记录;
(2)获取查询结果res并处理完毕,必须释放res,否则会造成内存泄露
(3)在单线程时,步骤初始化MySQL库和数据库连接句柄可合并, 由mysql_init()来处理。该函数会自动调用函数mysql_library_init()来初始化MySQL库,同时初始化连接句柄。
4 多线程环境下的数据库访问
多线程环境下的数据库访问需要保证线程安全。Windows版本的MySQL C
API函数都是线程安全的,除了mysql_library_init(),而我们刚才的代码中使用的mysql_init()函数会自动调用函数
mysql_library_init()来初始化MySQL库,因此在多线程环境下,需要不同的初始化代码和清理代码。具体过程如下:
(1)在主函数中调用mysql_library_init()来初始化MySQL库;
(2)启动各数据库访问线程
(3)主函数等待各个线程的结束
(4)调用mysql_library_end ()清理MySQL库。
其中数据库访问线程的代码和单线程数据库访问代码类似,但是需要如下变化:
(1)单线程中的第2步初始化MySQL库和数据库连接句柄,不能再使用mysql_init(),代码应作如下修改:
//初始化线程
my_init();
mysql_thread_init();
//初始化myData
myData = malloc(sizeof(MYSQL));
memset(&myData, 0, sizeof(MYSQL))
(2)上述初始化myData,只是将myData所有成员设为0,如果有需要可以根据具体情况设置该结构成员的值,例myData->reconnect= 1,其作用是设置数据库连接属性为重连接,即当数据库连接断开时,自动重新连接;
(3)单线程中的第6步不在需要,改为结束线程的清理工作,即调用mysql_thread_end()函数。
5 总结
综上所述,使用C
API访问MySQL数据库在不同线程环境下的区别主要在于初始化和访问结束后清理代码,也就是说除了初始化和清理代码,MySQL提供给我们的C
API函数都是线程安全的。最后需要有一点说明,使用C
API访问数据库可以提高数据库的访问效率,但并不是所有的数据库项目都适合这种方式,该方式适合需要大量实时并发处理的数据库项目,例如网络游戏的数据
库项目,对于有此需求的数据库项目可参考本文。
参考文献:
[1]MySQL AB,MySQL 5.0 Reference Manual.
注:“本文中所涉及到的图表、公式注解等形式请以PDF格式阅读原文。”
如何开启系统端口
--------------------------------------------------------------------------------
win本身大部分的端口应该都是开的吧,只能是关哪个端口。
试试这片文章:
查看端口
在Windows 2000/XP/Server 2003中要查看端口,可以使用Netstat命令:
依次点击“开始→运行”,键入“cmd”并回车,打开命令提示符窗口。在命令提示符状态下键入“netstat -a -n”,按下回车键后就可以看到以数字形式显示的TCP和UDP连接的端口号及状态。
小知识:Netstat命令用法
命令格式:Netstat -a -e -n -o -s
-a 表示显示所有活动的TCP连接以及计算机监听的TCP和UDP端口。
-e 表示显示以太网发送和接收的字节数、数据包数等。
-n 表示只以数字形式显示所有活动的TCP连接的地址和端口号。
-o 表示显示活动的TCP连接并包括每个连接的进程ID(PID)。
-s 表示按协议显示各种连接的统计信息,包括端口号。
关闭/开启端口
在介绍各种端口的作用前,这里先介绍一下在Windows中如何关闭/打开端口,因为默认的情况下,有很多不安全的或没有什么用的端口是开启的,
比如Telnet服务的23端口、FTP服务的21端口、SMTP服务的25端口、RPC服务的135端口等等。为了保证系统的安全性,我们可以通过下面
的方法来关闭/开启端口。
关闭端口
比如在Windows
2000/XP中关闭SMTP服务的25端口,可以这样做:首先打开“控制面板”,双击“管理工具”,再双击“服务”。接着在打开的服务窗口中找到并双击
“Simple Mail Transfer Protocol
(SMTP)”服务,单击“停止”按钮来停止该服务,然后在“启动类型”中选择“已禁用”,最后单击“确定”按钮即可。这样,关闭了SMTP服务就相当于
关闭了对应的端口。
开启端口
如果要开启该端口只要先在“启动类型”选择“自动”,单击“确定”按钮,再打开该服务,在“服务状态”中单击“启动”按钮即可启用该端口,最后,单击“确定”按钮即可。
21端口:21端口主要用于FTP(File Transfer Protocol,文件传输协议)服务。
23端口:23端口主要用于Telnet(远程登录)服务,是Internet上普遍采用的登录和仿真程序。
25端口:25端口为SMTP(Simple Mail Transfer
Protocol,简单邮件传输协议)服务器所开放,主要用于发送邮件,如今绝大多数邮件服务器都使用该协议。
53端口:53端口为DNS(Domain Name
Server,域名服务器)服务器所开放,主要用于域名解析,DNS服务在NT系统中使用的最为广泛。
67、68端口:67、68端口分别是为Bootp服务的Bootstrap Protocol
Server(引导程序协议服务端)和Bootstrap Protocol Client(引导程序协议客户端)开放的端口。
69端口:TFTP是Cisco公司开发的一个简单文件传输协议,类似于FTP。
79端口:79端口是为Finger服务开放的,主要用于查询远程主机在线用户、操作系统类型以及是否缓冲区溢出等用户的详细信息。
80端口:80端口是为HTTP(HyperText Transport
Protocol,超文本传输协议)开放的,这是上网冲浪使用最多的协议,主要用于在WWW(World Wide
Web,万维网)服务上传输信息的协议。 99端口:99端口是用于一个名为“Metagram
Relay”(亚对策延时)的服务,该服务比较少见,一般是用不到的。 109、110端口:109端口是为POP2(Post Office
Protocol Version
2,邮局协议2)服务开放的,110端口是为POP3(邮件协议3)服务开放的,POP2、POP3都是主要用于接收邮件的。
111端口:111端口是SUN公司的RPC(Remote Procedure
Call,远程过程调用)服务所开放的端口,主要用于分布式系统中不同计算机的内部进程通信,RPC在多种网络服务中都是很重要的组件。
113端口:113端口主要用于Windows的“Authentication Service”(验证服务)。
119端口:119端口是为“Network News Transfer Protocol”(网络新闻组传输协议,简称NNTP)开放的。
135端口:135端口主要用于使用RPC(Remote Procedure
Call,远程过程调用)协议并提供DCOM(分布式组件对象模型)服务。 137端口:137端口主要用于“NetBIOS Name
Service”(NetBIOS名称服务)。 139端口:139端口是为“NetBIOS Session
Service”提供的,主要用于提供Windows文件和打印机共享以及Unix中的Samba服务。
143端口:143端口主要是用于“Internet Message Access
Protocol”v2(Internet消息访问协议,简称IMAP)。 161端口:161端口是用于“Simple Network
Management Protocol”(简单网络管理协议,简称SNMP)。
443端口:43端口即网页浏览端口,主要是用于HTTPS服务,是提供加密和通过安全端口传输的另一种HTTP。
554端口:554端口默认情况下用于“Real Time Streaming Protocol”(实时流协议,简称RTSP)。
1024端口:1024端口一般不固定分配给某个服务,在英文中的解释是“Reserved”(保留)。
1080端口:1080端口是Socks代理服务使用的端口,大家平时上网使用的WWW服务使用的是HTTP协议的代理服务。
1755端口:1755端口默认情况下用于“Microsoft Media Server”(微软媒体服务器,简称MMS)。
4000端口:4000端口是用于大家经常使用的QQ聊天工具的,再细说就是为QQ客户端开放的端口,QQ服务端使用的端口是8000。
5554端口:在今年4月30日就报道出现了一种针对微软lsass服务的新蠕虫病毒——震荡波(Worm.Sasser),该病毒可以利用TCP
5554端口开启一个FTP服务,主要被用于病毒的传播。
5632端口:5632端口是被大家所熟悉的远程控制软件pcAnywhere所开启的端口。
8080端口:8080端口同80端口,是被用于WWW代理服务的,可以实现网页端口概念
在网络技术中,端口(Port)大致有两种意思:一是物理意义上的端口,比如,ADSL
Modem、集线器、交换机、路由器用于连接其他网络设备的接口,如RJ-45端口、SC端口等等。二是逻辑意义上的端口,一般是指TCP/IP协议中的
端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。我们这里将要介绍的就是逻辑意义上的端口。
端口分类 逻辑意义上的端口有多种分类标准,下面将介绍两种常见的分类: 1. 按端口号分布划分 (1)知名端口(Well-Known
Ports)
知名端口即众所周知的端口号,范围从0到1023,这些端口号一般固定分配给一些服务。比如21端口分配给FTP服务,25端口分配给SMTP(简单邮件
传输协议)服务,80端口分配给HTTP服务,135端口分配给RPC(远程过程调用)服务等等。 (2)动态端口(Dynamic Ports)
动态端口的范围从1024到65535,这些端口号一般不固定分配给某个服务,也就是说许多服务都可以使用这些端口。只要运行的程序向系统提出访问网络的
申请,那么系统就可以从这些端口号中分配一个供该程序使用。比如1024端口就是分配给第一个向系统发出申请的程序。在关闭程序进程后,就会释放所占用的
端口号。 不过,动态端口也常常被病毒木马程序所利用,如冰河默认连接端口是7626、WAY 2.4是8011、Netspy
3.0是7306、YAI病毒是1024等等。 2. 按协议类型划分
按协议类型划分,可以分为TCP、UDP、IP和ICMP(Internet控制消息协议)等端口。下面主要介绍TCP和UDP端口:
(1)TCP端口
TCP端口,即传输控制协议端口,需要在客户端和服务器之间建立连接,这样可以提供可靠的数据传输。常见的包括FTP服务的21端口,Telnet服务的
23端口,SMTP服务的25端口,以及HTTP服务的80端口等等。 (2)UDP端口
UDP端口,即用户数据包协议端口,无需在客户端和服务器之间建立连接,安全性得不到保障。常见的有DNS服务的53端口,SNMP(简单网络管理协议)
服务的161端口,QQ使用的8000和4000端口等等。查看端口 在Windows 2000/XP/Server
2003中要查看端口,可以使用Netstat命令:
依次点击“开始→运行”,键入“cmd”并回车,打开命令提示符窗口。在命令提示符状态下键入“netstat -a
-n”,按下回车键后就可以看到以数字形式显示的TCP和UDP连接的端口号及状态(如图)。 小知识:Netstat命令用法
命令格式:Netstat -a -e -n -o -s -a
表示显示所有活动的TCP连接以及计算机监听的TCP和UDP端口。 -e 表示显示以太网发送和接收的字节数、数据包数等。 -n
表示只以数字形式显示所有活动的TCP连接的地址和端口号。 -o 表示显示活动的TCP连接并包括每个连接的进程ID(PID)。 -s
表示按协议显示各种连接的统计信息,包括端口号。 关闭/开启端口
在介绍各种端口的作用前,这里先介绍一下在Windows中如何关闭/打开端口,因为默认的情况下,有很多不安全的或没有什么用的端口是开启的,比如
Telnet服务的23端口、FTP服务的21端口、SMTP服务的25端口、RPC服务的135端口等等。为了保证系统的安全性,我们可以通过下面的方
法来关闭/开启端口。 关闭端口 比如在Windows
2000/XP中关闭SMTP服务的25端口,可以这样做:首先打开“控制面板”,双击“管理工具”,再双击“服务”。接着在打开的服务窗口中找到并双击
“Simple Mail Transfer Protocol
(SMTP)”服务,单击“停止”按钮来停止该服务,然后在“启动类型”中选择“已禁用”,最后单击“确定”按钮即可。这样,关闭了SMTP服务就相当于
关闭了对应的端口。 开启端口
如果要开启该端口只要先在“启动类型”选择“自动”,单击“确定”按钮,再打开该服务,在“服务状态”中单击“启动”按钮即可启用该端口,最后,单击“确
定”按钮即可。 提示:在Windows 98中没有“服务”选项,你可以使用防火墙的规则设置功能来关闭/开启端口。 79端口
端口说明:79端口是为Finger服务开放的,主要用于查询远程主机在线用户、操作系统类型以及是否缓冲区溢出等用户的详细信息。比如要显示远程计算机www.abc.com上的user01用户的信息,可以在命令行中键入“finger user01@www.abc.com”
即可。
端口漏洞:一般黑客要攻击对方的计算机,都是通过相应的端口扫描工具来获得相关信息,比如使用“流光”就可以利用79端口来扫描远程计算机操作系统版本,
获得用户信息,还能探测已知的缓冲区溢出错误。这样,就容易遭遇到黑客的攻击。而且,79端口还被Firehotcker木马作为默认的端口。
操作建议:建议关闭该端口。 80端口 端口说明:80端口是为HTTP(HyperText Transport
Protocol,超文本传输协议)开放的,这是上网冲浪使用最多的协议,主要用于在WWW(World Wide
Web,万维网)服务上传输信息的协议。我们可以通过HTTP地址加“:80”(即常说的“网址”)来访问网站的,比如http://www.cce.com.cn:80,
因为浏览网页服务默认的端口号是80,所以只要输入网址,不用输入“:80”。
端口漏洞:有些木马程序可以利用80端口来攻击计算机的,比如Executor、RingZero等。
操作建议:为了能正常上网冲浪,我们必须开启80端口。 109与110端口 端口说明:109端口是为POP2(Post Office
Protocol Version
2,邮局协议2)服务开放的,110端口是为POP3(邮件协议3)服务开放的,POP2、POP3都是主要用于接收邮件的,目前POP3使用的比较多,
许多服务器都同时支持POP2和POP3。客户端可以使用POP3协议来访问服务端的邮件服务,如今ISP的绝大多数邮件服务器都是使用该协议。在使用电
子邮件客户端程序的时候,会要求输入POP3服务器地址,默认情况下使用的就是110端口(如图)。
端口漏洞:POP2、POP3在提供邮件接收服务的同时,也出现了不少的漏洞。单单POP3服务在用户名和密码交换缓冲区溢出的漏洞就不少于20个,比如
WebEasyMail POP3
Server合法用户名信息泄露漏洞,通过该漏洞远程攻击者可以验证用户账户的存在。另外,110端口也被ProMail
trojan等木马程序所利用,通过110端口可以窃取POP账号用户名和密码。 操作建议:如果是执行邮件服务器,可以打开该端口。 135端口
端口说明:135端口主要用于使用RPC(Remote Procedure
Call,远程过程调用)协议并提供DCOM(分布式组件对象模型)服务,通过RPC可以保证在一台计算机上运行的程序可以顺利地执行远程计算机上的代
码;使用DCOM可以通过网络直接进行通信,能够跨包括HTTP协议在内的多种网络传输。 端口漏洞:相信去年很多Windows
2000和Windows
XP用户都中了“冲击波”病毒,该病毒就是利用RPC漏洞来攻击计算机的。RPC本身在处理通过TCP/IP的消息交换部分有一个漏洞,该漏洞是由于错误
地处理格式不正确的消息造成的。该漏洞会影响到RPC与DCOM之间的一个接口,该接口侦听的端口就是135。
操作建议:为了避免“冲击波”病毒的攻击,建议关闭该端口 137端口 端口说明:137端口主要用于“NetBIOS Name
Service”(NetBIOS名称服务),属于UDP端口,使用者只需要向局域网或互联网上的某台计算机的137端口发送一个请求,就可以获取该计算
机的名称、注册用户名,以及是否安装主域控制器、IIS是否正在运行等信息。
端口漏洞:因为是UDP端口,对于攻击者来说,通过发送请求很容易就获取目标计算机的相关信息,有些信息是直接可以被利用,并分析漏洞的,比如IIS服
务。另外,通过捕获正在利用137端口进行通信的信息包,还可能得到目标计算机的启动和关闭的时间,这样就可以利用专门的工具来攻击。
操作建议:建议关闭该端口。 139端口 端口说明:139端口是为“NetBIOS Session
Service”提供的,主要用于提供Windows文件和打印机共享以及Unix中的Samba服务。在Windows中要在局域网中进行文件的共享,
必须使用该服务。比如在Windows
98中,可以打开“控制面板”,双击“网络”图标,在“配置”选项卡中单击“文件及打印共享”按钮选中相应的设置就可以安装启用该服务;在Windows
2000/XP中,可以打开“控制面板”,双击“网络连接”图标,打开本地连接属性;接着,在属性窗口的“常规”选项卡中选择“Internet协议
(TCP/IP)”,单击“属性”按钮;然后在打开的窗口中,单击“高级”按钮;在“高级TCP/IP设置”窗口中选择“WINS”选项卡,在
“NetBIOS设置”区域中启用TCP/IP上的NetBIOS。
端口漏洞:开启139端口虽然可以提供共享服务,但是常常被攻击者所利用进行攻击,比如使用流光、SuperScan等端口扫描工具,可以扫描目标计算机
的139端口,如果发现有漏洞,可以试图获取用户名和密码,这是非常危险的
MySQL:无法远程登入MySQL Server
尝试用MySQL Adminstrator GUI Tool登入MySQL
Server,Server却回复错误讯息:Host '60-248-32-13.HINET-IP.hinet.net' is not
allowed to connect to this
MySQL server
这个是因为权限的问题,处理方式如下:
shell>mysql --user=root -p
输入密码
mysql>use mysql
mysql>GRANT SELECT,INSERT,UPDATE,DELETE ON [db_name].* TO [username]@[ipadd] identified by '[password]';
[username]:远程登入的使用者代码
[db_name]:表示欲开放给使用者的数据库称
[password]:远程登入的使用者密码
[ipadd]:IP地址或者IP反查后的DNS Name,此例的内容需填入'60-248-32-13.HINET-IP.hinet.net' ,包函上引号(')
(其实就是在远端服务器上执行,地址填写本地主机的ip地址。)
如果希望开放所有权限的话请执行:
mysql>update
user set select_priv='Y' , Insert_priv='Y', Update_priv='Y',
delete_priv='Y', Create_priv='Y', Drop_priv='Y',Reload_priv='Y',
shutdown_priv='Y', Process_priv='Y', File_priv='Y', Grant_priv='Y',
references_priv='Y',Index_priv='Y', Alter_priv='Y', Show_db_priv='Y',
Super_priv='Y',Create_tmp_table_priv='Y',Lock_tables_priv='Y',
Execute_priv='Y',Repl_slave_priv='Y',Repl_client_priv='Y' where
user='[username]';
如何解决客户端与服务器端的连接(mysql) :xxx.xxx.xxx.xxx is not allowed to connect to this mysql serv
这两天搞MySQL,遇到一些问题,怕忘掉,放上来,留着备用
这个方法是在google上搜出来的,不过他是转自CSDN,^_^
1、进入mysql,创建一个新用户xuys:
格式:grant 权限 on 数据库名.表名 用户@登录主机 identified by "用户密码";
grant select,update,insert,delete on *.* to xuys@192.168.88.234 identified by "xuys1234";
查看结果,执行:
use mysql;
select host,user,password from user;
可以看到在user表中已有刚才创建的xuys用户。host字段表示登录的主机,其值可以用IP,也可用主机名,
将host字段的值改为%就表示在任何客户端机器上能以xuys用户登录到mysql服务器,建议在开发时设为%。
update user set host = '%' where user = 'xuys';
2、 ./mysqladmin -uroot -p21century reload
./mysqladmin -uroot -p21century shutdown
3、./mysqld_safe --user-root &
记住:对授权表的任何修改都需要重新reload,即执行第3步。
如果经过以上3个步骤还是无法从客户端连接,请执行以下操作,在mysql数据库的db表中插入一条记录:
use mysql;
insert into db values('192.168.88.234','%','xuys','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
update db set host = '%' where user = 'xuys';
重复执行上面的第2、3步。
大概是两年前,我从我一个考研的朋友那里听到关于cvs和版本控制这两个词,当时他还教了我怎样在windows平台下配置wincvs和cvsnt。可
惜我当时并不在意这个,弄得现在配置这个东西花了我两天的时间,值得安慰的是在参考了众多网友的经验之后总算配置成功。为此把我的经验和教训贴出来以表示
对网友们的谢意(很抱歉的是当时只顾着看怎么配置没有记下各位网友的名字,ps自己一下)和对自己的鼓励。以后会把如何在开发过程中的使用贴出来。本文主
要参考资料是:吴炎溪 Email:Yanxi-Wu@21cn.com的《cvs服务器与wincvs的配置与使用》,发在chinaunix上。
我配置时服务器是redhat linux 9,客户端是windows xp和wincvs。这里假定读者已经安装好了redhat linux
9和wincvs,如果不知道怎么安装可以到网上搜一下。redhat linux
9的安装我使用的完全安装,就是把光盘里带的所有东西都安装上了。这样的话所有的服务器和服务应该都有了,为了偷懒我还把linux上的防火墙给关掉了,
我是内部局域网使用,如果不是的话千万不要把防火墙关了。(再ps自己一下)
一、linux下的cvs服务器配置
1、查看/etc/services文件:
首先要看看/etc/services这个文件,以确认cvs服务和端口已经打开:
cvspserver 2401/tcp # cvs client/server operations
cvspserver 2401/udp # cvs client/server operations
2、配置xinetd,用xinetd来启动cvs服务器:
进入到/etc/xinetd.d/目录,在此目录下编辑一个名字为cvspserver的文本文件,使用cvspserver作为文件名是因为在/etc/services中的入口名字是cvspserver。编辑如下:
service cvspserver
{
disable = no
protocol = tcp
socket_type = stream
port = 2401
wait = no
user = root
env = HOME=
server = /usr/bin/cvs
server_args = -f --allow-root=/home/cvsroot pserver
}
注意:a、service后面的名称一定要和你在/etc/service文件中的cvs服务名称一样;b、env = HOME=这一行的目的就是为了解决在执行一些cvs操作时产生的读取/root/.cvsignore文件的错误,上面env那行的意思就是在运行cvs服务的时候将环境变量HOME置空,这样虽然执行cvs的用户是root,但是由于没有了HOME这个环境变量,所以cvs就不会在去读取/root/.cvsignore文件了。
3、配置cvs用户组和cvsroot用户
首先建立一个用户组cvs,记下cvs组ID。然后添加一个用户cvsroot,然后修改/etc/passwd文件,把cvsroot用户的组ID改为
刚才新建的cvs组的组ID。这样在/home目录下就会有一个/cvsroot目录。修改/home/cvsroot的权限:#chomd 771
/home/cvsroot
4、对cvs进行初始化:
要使用cvs服务器首先要初始化cvs服务器的根目录,这样以后创建的cvs项目都将建立在这个目录下:# cvs -d /home/cvsroot init
5、登录cvs服务器(在linux下登录):
#cvs -d :pserver:cvsroot@host:/home/cvsroot login
CVS password://输入用户cvsroot的口令;
如果没有出现其它的任何提示就表示登录成功了,否则要根据提示进行相应的修改。 下面对登录命令的语法进行说明:
其中,:pserver表示采用pserver方式进行用户登录认证,一般的CVS服务器都采用这
种方式,当然也可以采用其它方式,具体参考相应的资料;
:cvsroot表示要登录的用户名,只要是cvs组的成员都可以,如:cather;
@host表示要登录的服务器,可以是DNS名,也可以是IP地址,如:10.104.1.204;
:/home/cvsroot表示CVS在服务器上的目录,也可以是其它目录(由第6中你所
指定的用来做init初始化的目录决定);
提示:也可以把export CVSROOT=":pserver:jchuang"@192.168.0.8:/home/cvsroot这一句直
接写在用户的初始化文件中(如:.bash_profile),这样用户每次登录时,只需输入:
#cvs login
然后输入相应的口令就可以登录到cvs服务器上。
b、如果是本地登录,可以直接把export CVSROOT="/home/cvsroot"这一句写在用户的初
始化文件如:.bash_profile中;然后直接输入#cvs login,再输入相应的口令就可以登录到cvs服务器上了。
二、WinCVS的配置
1、WinCVS简介:
WinCVS是CVS的一个客户端软件,它运行在Windows上,用来在Windows上登录CVS服务器,然后进行一些CVS相关的操作与管理。由于当前很多的企业内部都采用Linux/Unix做服务器,而用Windows做客户端,所以,WinCVS与CVS服务器配合使用将组成最强有力的版本控制与管理的系统之一。
2、WinCVS的下载与安装;
最新的WinCVS可以从http://sourceforge.net/project/showfiles.php?group_id=10072地址下载到,也可以在http://sourceforge.net/project 上下载到最新的或其它版本的WinCVS。下载到相应的版本后根据向导进行安装,已经要使用CVS的用户,安装这个WinCVS应该没什么问题吧!
3、配置WinCVS:
a、一般选项的设置,选择Admin->references…,出现如下界面:
第一、Authentication:用来配置cvs服务器的认证方式,可以从下拉框中选择其它的认证方式,不过一般只要选择默认的pserver方式就可以,要注意的是必须与cvs服务器配置时所指定的认证方式一致;
第二、Path:用来配置cvs在服务器上的主目录路径,也就是服务器上用进行cvs初始化的目录,如:/home/cvsroot;
第三、Host Address:用来配置cvs服务器所在服务器的地址,可以是IP地址,也可以是DNS名,如:10.104.1.204;
第四、User name:用来配置要使用些WinCVS来登录CVS服务器的用户名,如:cvsyxwu,用户的登录必须由管理员把其添加cvs用户组中;
第五、CVSROOT:此项一般都不需要用户进行修改,用户在输入上边的几个选项时,系统将自动根据用户的输入生成此项的相应内容。
b、全局选项的设置,在上一个界面上选择“Globals”:
此项的配置主要是要注意这几选项:
第一,Checkout read-only不要选上,否则,checkout出来的源代码将不允许用户进行
修改,并且此选项默认是选中的;
第二,Prune (remove) empty directories也不要选上,否则,会自动删除空目录;
第三,对一般配置没有特殊要求的,把Dirty files support、Supply control when adding
与TCP/IP compression选项选中;
4、登录服务器:
选择Admin->;login,将出现如下对话框要求用户输入登录口令
输入口令后,选择“OK”按钮,如果CVS服务器与WinCVS的配置都没出错的话,将在CVS的状态栏中提示:
cvs -z9 -d :pserver:cvsyxwu@10.104.1.204:/home/cvsroot login
Logging in to :pserver:cvsyxwu@10.104.1.204:2401/home/cvsroot
***** CVS exited normally with code 0 *****
code 0表示正确的登录;而如果出错的话,将是code 1,那么要根据错误的提示进行相应的修改。
Windows系统集成了无数的工具,它们各司其职,满足用户不同的应用需求。其实这些工具“多才多艺”,如果你有足够的想象力并且善于挖掘,你会发现它们除了本行之外还可以帮我们杀毒。不信?你看吧!
一、任务管理器给病毒背后一刀
Windows任务管理器是大家对进程进行管理的主要工具,在它的“进程”选项卡中能查看当前系统进程信息。在默认设置下,一般只能看到映像名称、用户名、CPU占用、内存使用等几项,而更多如I/O读写、虚拟内存大小等信息却被隐藏了起来。可别小看了这些被隐藏的信息,当系统出现莫名其妙的故障时,没准就能从它们中间找出突破口。
1.查杀会自动消失的双进程木马
前段时间朋友的电脑中了某木马,通过任务管理器查出该木马进程为“system.exe”,终止它后再刷新,它又会复活。进入安全模式把c:\windows\system32\system.exe删除,重启后它又会重新加载,怎么也无法彻底清除它。从此现象来看,朋友中的应该是双进程木马。这种木马有监护进程,会定时进行扫描,一旦发现被监护的进程遭到查杀就会复活它。而且现在很多双进程木马互为监视,互相复活。因此查杀的关键是找到这“互相依靠”的两个木马文件。借助任务管理器的PID标识可以找到木马进程。
调出Windows任务管理器,首先在“查看→选择列”中勾选“PID(进程标识符)”,这样返回任务管理器窗口后可以看到每一个进程的PID标识。这样当我们终止一个进程,它再生后通过PID标识就可以找到再生它的父进程。启动命令提示符窗口,执行“taskkill
/im system.exe
/f”命令。刷新一下电脑后重新输入上述命令如图1,可以看到这次终止的system.exe进程的PID为1536,它属于PID为676的某个进程。也就是说PID为1536的system.exe进程是由PID为676的进程创建的。返回任务管理器,通过查询进程PID得知它就是“internet.exe”进程进程。(如图)
找到了元凶就好办了,现在重新启动系统进入安全模式,使用搜索功能找到木马文件c:\windows\internet.exe
,然后将它们删除即可。前面无法删除system.exe,主要是由于没有找到internet.exe(且没有删除其启动键值),导致重新进入系统后internet.exe复活木马。
2.揪出狂写硬盘的P2P程序
单位一电脑一开机上网就发现硬盘灯一直闪个不停,硬盘狂旋转。显然是本机有什么程序正在进行数据的读取,但是反复杀毒也没发现病毒、木马等恶意程序。
打开该电脑并上网,按Ctrl+Alt+Del键启动了任务管理器,切换到“进程”选项卡,点击菜单命令“查看→选择列”,同时勾选上“I/O写入”和“I/O写入字节”两项。确定后返回任务管理器,发现一个陌生的进程hidel.exe,虽然它占用的CPU和内存并不是特别大,但是I/O的写入量却大得惊人,看来就是它在捣鬼了,赶紧右击它并选择“结束进程”终止,果然硬盘读写恢复正常了。
二、系统备份工具杀毒于无形
笔者曾遭遇一个无法删除的病毒“C:\Program
Files\Common
Files\PCSuite\rasdf.exe”,同时也无法复制这个文件,如何清除它。笔者通过系统备份工具清除了该病毒,操作过程如下:
第一步:单击“开始→所有程序→附件→系统工具→备份”,打开备份或还原向导窗口,备份项目选择“让我选择要备份的内容”,定位到“C:\Program
Files\Common
Files\PCSuite”。
第二步:继续执行备份向导操作,将备份文件保存为“g:\virus.bkf”,备份选项勾选“使用卷阴影复制”,剩余操作按默认设置完成备份。
第三步:双击“g:\virus.bak”,打开备份或还原向导,把备份还原到“g:\virus”。接着打开“g:\virus”,使用记事本打开病毒文件“rasdf.exe”,然后随便删除其中几行代码并保存,这样病毒就被我们使用记事本破坏了(它再也无法运行)。
第四步:操作同上,重新制作“k:\virus”的备份为“k:\virus1.bkf”。然后启动还原向导,还原位置选择“C:\Program
Files\Common
Files\PCSuite\”,还原选项选择“替换现有文件”。这样,虽然当前病毒正在运行,但备份组件仍然可以使用坏的病毒文件替换当前病毒。还原完成后,系统提示重新启动,重启后病毒就不会启动了(因为它已被记事本破坏)。
三、记事本借刀杀人
1.双进程木马的查杀
现在,越来越多的木马采用双进程守护技术保护自己,就是两个拥有同样功能的代码程序,不断地检测对方是否已经被别人终止,如果发现对方已经被终止了,那么又开始创建对方,这给我们的查杀带来很大的困难。不过,此类木马也有“软肋”,它只通过进程列表进程名称来判断被守护进程是否存在。这样,我们只要用记事本程序来替代木马进程,就可以达到“欺骗”守护进程的目的。
下面以某变种木马的查杀为例。中招该木马后,木马的“internet.exe”和“systemtray.exe”两个进程会互相监视。当然,我们中招的时候大多不知道木马具体的监护进程。不过,通过进程名称可以知道,“systemtray.exe”是异常的进程,因为系统正常进程中没有该进程。下面使用替换方法来查杀该木马。
第一步:单击“开始→运行”,输入“Msinfo32”打开系统信息窗口,展开“系统摘要→软件环境→正在运行任务”,这里可以看到“systemtray.exe”路径在“C:\Windows\System32”下。
第二步:打开“C:\Windows\System32”,复制记事本程序“notepad.exe”到“D:\”
,同时重命名为“systemtray.exe”。
第三步:打开记事本程序,输入下列代码,保存为“shadu.bat”,放置在桌面(括号为注释,无须输入):
@echo
off
Taskkill /f /im systemtray.exe
(使用taskkill命令强行终止“systemtray.exe”进程)
Delete
C:\Windows\System32\systemtray.exe (删除病毒文件)
Copy d:\systemtray.exe
C:\Windows\System32\(替换病毒文件)
第四步:现在只要在桌面运行“shadu.bat”,系统会将“systemtray.exe”进程终止并删除,同时把改名的记事本程序复制到系统目录。这样,守护进程会“误以为”被守护进程还存在,它会立刻启动一个记事本程序。
第五步:接下来我们只要找出监视进程并删除即可,在命令提示符输入:
“taskkill
/f /im systemtray.exe ”,将守护进程再生的“systemtray.exe”终止,可以看到“systemtray.exe”进程是由“PID
3288的进程”创建的,打开任务管理器可以看到“PID
3288的进程”为“internet.exe”,这就是再生进程的“元凶”。
第六步:按照第一步方式,打开系统信息窗口可以看到“internet.exe”也位于系统目录,终止“internet.exe”进程并进入系统目录把上述两个文件删除即可。
2.使病毒失效并删除
大家知道,文件都是由编码组成的,记事本程序理论上可以打开任意文件(只不过有些会显示为乱码)。我们可以将病毒打开方式关联到记事本,使之启动后变成由记事本打开,失去作恶的功能。比如,一些顽固病毒常常会在注册表的“HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run”等启动位置生成难以删除的键值,达到恶意启动的目的。下面使用记事本来“废”掉病毒的生命力。
第一步:启动命令提示符,输入“ftype
exefile=notepad.exe
%1”,把所有EXE程序打开方式关联到记事本程序,重启系统后我们会发现桌面自动启动好几个程序,这里包括系统正常的程序如输入法、音量调整程序等,当然也包括恶意启动的流氓程序,不过现在都被记事本打开了。
第二步:根据记事本窗口标题找到病毒程序,比如上例的systemtray.exe程序,找到这个记事本窗口后,单击“文件→另存为”,我们就可以看到病毒具体路径在“C:\Windows\System32”下。现在关掉记事本窗口,按上述路径提示进入系统目录删除病毒即可。
第三步:删除病毒后就可以删除病毒启动键值了,接着重启电脑,按住F8,然后在安全模式菜单选择“带命令提示的安全模式”,进入系统后会自动打开命令提示符。输入“ftype
exefile="%1"%*”恢复exe文件打开方式即可。
四、注册表映像劫持让病毒没脾气
现在病毒都会采用IFO的技术,通俗的讲法是映像劫持,利用的是注册表中的如下键值
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Image File Execution
Options位置来改变程序调用的,而病毒却利用此处将正常的杀毒软件给偷换成病毒程序。恰恰相反,让我们自己可以利用此处欺瞒病毒木马,让它实效。可谓,瞒天过海,还治其人。
下面我们以屏蔽某未知病毒KAVSVC.EXE为例,操作方法如下:
第一步:先建立以下一文本文件,输入以下内容,另存为1.reg
Windows
Registry Editor Version
5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Image File Execution
Options\KAVSVC.EXE]
"Debugger"="d:\\1.exe"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Image File Execution
Options\KAVSVC.EXE]
"Debugger"="d:\\1.exe"
(注:第一行代码下有空行。)
第二步:双击导入该reg文件后,确定。
第三步:点“开始→运行”后,输入KAVSVC.EXE。
提示:1.exe可以是任意无用的文件,是我们随意创建一个文本文件后将后缀名.txt改为.exe的,
总结:当我们饱受病毒木马的折磨,在杀毒软件无能为力或者感觉“杀鸡焉用宰牛刀”时,不妨运用系统工具进行病毒木马的查杀,说不定会起到意想不到的效果