/* 客户端退出处理 */ void handle_recover(int sig) { int i; if (sig == SIGCHLD) { pid_t pid = wait(0); printf("退出的子进程 pid = [%d]\n\n", pid); char tempIP[20]="",tempPid[10]=""; sprintf(tempPid, "%d", pid); // 通过进程pid获取ip strcpy(tempIP, (char *)hash_getval(hash_pid_ip, tempPid, H_GET_VAL)); if(tempIP != NULL) { printf("开始重新统计链接数:\n"); printf("退出客户端IP=%s\n", tempIP); //得到指定IP的已连接数 i = atoi((char *)hash_getval(hash_ip_count, tempIP, H_GET_VAL)); if ( i > 1 ) { // 连接数至少是2 则减1 hash_del(hash_ip_count, tempIP, H_DEL_MINUS);//删除 1代表数量大于1 }else { // 链接数为1 删除节点 hash_del(hash_ip_count, tempIP, H_DEL_DESTROY); } printf("哈希表 IP连接数 【删除】 %s\n", tempIP); hash_del(hash_pid_ip, tempPid, H_DEL_DESTROY); printf("哈希表 进程IP联系 【删除】 %s\n", tempPid); }else { printf("哈希表 连接数统计失败!\n"); } printf("\n当前客户端列表\n"); for(i=0;i<HASH_MAX;i++) { if(hash_ip_count[i]!=NULL) { printf("客户端ip=%-15s 连接数=%-20s\n",hash_ip_count[i]->key,hash_ip_count[i]->val); } } printf("总计 %d 个链接\n", get_hash_length(hash_pid_ip) ); } }
char *tdb1_summary(struct tdb_context *tdb) { tdb1_off_t off, rec_off; struct tally freet, keys, data, dead, extra, hash, uncoal; struct tdb1_record rec; char *ret = NULL; bool locked; size_t len, unc = 0; struct tdb1_record recovery; /* We may have a write lock already, so don't lock. */ if (tdb->file->allrecord_lock.count != 0) { locked = false; } else { if (tdb_lockall_read(tdb) != TDB_SUCCESS) return NULL; locked = true; } if (tdb1_recovery_area(tdb, tdb->tdb1.io, &rec_off, &recovery) != 0) { goto unlock; } tally1_init(&freet); tally1_init(&keys); tally1_init(&data); tally1_init(&dead); tally1_init(&extra); tally1_init(&hash); tally1_init(&uncoal); for (off = TDB1_DATA_START(tdb->tdb1.header.hash_size); off < tdb->file->map_size - 1; off += sizeof(rec) + rec.rec_len) { if (tdb->tdb1.io->tdb1_read(tdb, off, &rec, sizeof(rec), TDB1_DOCONV()) == -1) goto unlock; switch (rec.magic) { case TDB1_MAGIC: tally1_add(&keys, rec.key_len); tally1_add(&data, rec.data_len); tally1_add(&extra, rec.rec_len - (rec.key_len + rec.data_len)); if (unc > 1) tally1_add(&uncoal, unc - 1); unc = 0; break; case TDB1_FREE_MAGIC: tally1_add(&freet, rec.rec_len); unc++; break; /* If we crash after ftruncate, we can get zeroes or fill. */ case TDB1_RECOVERY_INVALID_MAGIC: case 0x42424242: unc++; /* If it's a valid recovery, we can trust rec_len. */ if (off != rec_off) { rec.rec_len = tdb1_dead_space(tdb, off) - sizeof(rec); } /* Fall through */ case TDB1_DEAD_MAGIC: tally1_add(&dead, rec.rec_len); break; default: tdb->last_error = tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR, "Unexpected record magic 0x%x" " at offset %d", rec.magic, off); goto unlock; } } if (unc > 1) tally1_add(&uncoal, unc - 1); for (off = 0; off < tdb->tdb1.header.hash_size; off++) tally1_add(&hash, get_hash_length(tdb, off)); /* 20 is max length of a %zu. */ len = strlen(SUMMARY_FORMAT1) + 35*20 + 1; ret = (char *)malloc(len); if (!ret) goto unlock; snprintf(ret, len, SUMMARY_FORMAT1, (tdb1_len_t)tdb->file->map_size, keys.total+data.total, keys.num, keys.min, tally1_mean(&keys), keys.max, data.min, tally1_mean(&data), data.max, extra.min, tally1_mean(&extra), extra.max, dead.num, dead.min, tally1_mean(&dead), dead.max, freet.num, freet.min, tally1_mean(&freet), freet.max, hash.num, hash.min, tally1_mean(&hash), hash.max, uncoal.total, uncoal.min, tally1_mean(&uncoal), uncoal.max, keys.total * 100.0 / tdb->file->map_size, data.total * 100.0 / tdb->file->map_size, extra.total * 100.0 / tdb->file->map_size, freet.total * 100.0 / tdb->file->map_size, dead.total * 100.0 / tdb->file->map_size, (keys.num + freet.num + dead.num) * (sizeof(struct tdb1_record) + sizeof(uint32_t)) * 100.0 / tdb->file->map_size, tdb->tdb1.header.hash_size * sizeof(tdb1_off_t) * 100.0 / (tdb1_len_t)tdb->file->map_size); unlock: if (locked) { tdb_unlockall_read(tdb); } return ret; }
_PUBLIC_ char *tdb_summary(struct tdb_context *tdb) { off_t file_size; tdb_off_t off, rec_off; struct tally freet, keys, data, dead, extra, hashval, uncoal; struct tdb_record rec; char *ret = NULL; bool locked; size_t unc = 0; int len; struct tdb_record recovery; /* Read-only databases use no locking at all: it's best-effort. * We may have a write lock already, so skip that case too. */ if (tdb->read_only || tdb->allrecord_lock.count != 0) { locked = false; } else { if (tdb_lockall_read(tdb) == -1) return NULL; locked = true; } if (tdb_recovery_area(tdb, tdb->methods, &rec_off, &recovery) != 0) { goto unlock; } tally_init(&freet); tally_init(&keys); tally_init(&data); tally_init(&dead); tally_init(&extra); tally_init(&hashval); tally_init(&uncoal); for (off = TDB_DATA_START(tdb->hash_size); off < tdb->map_size - 1; off += sizeof(rec) + rec.rec_len) { if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), DOCONV()) == -1) goto unlock; switch (rec.magic) { case TDB_MAGIC: tally_add(&keys, rec.key_len); tally_add(&data, rec.data_len); tally_add(&extra, rec.rec_len - (rec.key_len + rec.data_len)); if (unc > 1) tally_add(&uncoal, unc - 1); unc = 0; break; case TDB_FREE_MAGIC: tally_add(&freet, rec.rec_len); unc++; break; /* If we crash after ftruncate, we can get zeroes or fill. */ case TDB_RECOVERY_INVALID_MAGIC: case 0x42424242: unc++; /* If it's a valid recovery, we can trust rec_len. */ if (off != rec_off) { rec.rec_len = tdb_dead_space(tdb, off) - sizeof(rec); } /* Fall through */ case TDB_DEAD_MAGIC: tally_add(&dead, rec.rec_len); break; default: TDB_LOG((tdb, TDB_DEBUG_ERROR, "Unexpected record magic 0x%x at offset %u\n", rec.magic, off)); goto unlock; } } if (unc > 1) tally_add(&uncoal, unc - 1); for (off = 0; off < tdb->hash_size; off++) tally_add(&hashval, get_hash_length(tdb, off)); file_size = tdb->hdr_ofs + tdb->map_size; len = asprintf(&ret, SUMMARY_FORMAT, (unsigned long long)file_size, keys.total+data.total, (size_t)tdb->hdr_ofs, (size_t)tdb->map_size, keys.num, (tdb->hash_fn == tdb_jenkins_hash)?"yes":"no", (unsigned)tdb->feature_flags, TDB_SUPPORTED_FEATURE_FLAGS, (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX)?"yes":"no", keys.min, tally_mean(&keys), keys.max, data.min, tally_mean(&data), data.max, extra.min, tally_mean(&extra), extra.max, dead.num, dead.min, tally_mean(&dead), dead.max, freet.num, freet.min, tally_mean(&freet), freet.max, hashval.num, hashval.min, tally_mean(&hashval), hashval.max, uncoal.total, uncoal.min, tally_mean(&uncoal), uncoal.max, keys.total * 100.0 / file_size, data.total * 100.0 / file_size, extra.total * 100.0 / file_size, freet.total * 100.0 / file_size, dead.total * 100.0 / file_size, (keys.num + freet.num + dead.num) * (sizeof(struct tdb_record) + sizeof(uint32_t)) * 100.0 / file_size, tdb->hash_size * sizeof(tdb_off_t) * 100.0 / file_size); if (len == -1) { goto unlock; } unlock: if (locked) { tdb_unlockall_read(tdb); } return ret; }
/* ftp运行函数 */ int start() { //1.socket int listenfd = socket(AF_INET, SOCK_STREAM, 0); if(listenfd==-1) ERR_EXIT("socket"); //2.设置监听 ip/port struct sockaddr_in servaddr; memset(&servaddr, 0,sizeof(servaddr)); servaddr.sin_family = PF_INET;//AF_INET servaddr.sin_port = htons(PORT_LISTEN); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); socklen_t seraddrlen =sizeof(servaddr); //设置地址重用 int rel = serAddrReuse(listenfd); if (rel == -1) ERR_EXIT("setsockopt"); int res = bind(listenfd, (struct sockaddr*)&servaddr, seraddrlen); if(res==-1) ERR_EXIT("bind"); //3.listen侦听客户端的连接 res=listen(listenfd, 5); if(res==-1) ERR_EXIT("listen"); printf("-------------------------------------\n"); printf("| 服务器端配置文件读取成功\n"); printf("-------------------------------------\n"); printf("| 服务器端ip =[%s]\n", LOCAL_IP); printf("| 监听端口port =[%d]\n", PORT_LISTEN); printf("| 最大连接数 =[%d]\n", MAX_COUNT); printf("| 同ip最大连接数=[%d]\n", MAX_IP_COUNT); printf("| 限制下载速度 =[%dkb/s]\n", LIMIT_SPEED*10); printf("-------------------------------------\n"); //4.accept:接受客户端的连接,如果没有客户端连接进来, accept会阻塞,如果客户端连接进来了,accept会返回一个新的套接口,这个新的套接口就是与客户端进行数据通信的通道, 客户端的网络地址会填充进accept的第二个参数,第三个参数会是客户端地址的长度 pid_t pid; MAIN_PID = getpid(); // 安装进程回收信号 signal(SIGCHLD, handle_recover); while(1) { // 阻塞,等待接收 struct sockaddr_in cliaddr; memset(&cliaddr, 0,sizeof(cliaddr)); socklen_t cliaddrlen =sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen); if(connfd==-1) ERR_EXIT("accept"); char now_ip[20] = ""; strcpy(now_ip, inet_ntoa(cliaddr.sin_addr)); printf("\n建立新连接!\n"); printf("ip=%s\n", now_ip); printf("port=%d\n\n", ntohs(cliaddr.sin_port)); // 发送welcome至客户端 getpeername(connfd, ) write_loop(connfd, "220 welcome\r\n", strlen("220 welcome\r\n")); int conn_count=0, len=0; // 判断连接数控制 if ( (conn_count = getIpConn(now_ip)) >= MAX_IP_COUNT ) { printf("超过同ip连接数,当前为 %d 最大为 %d\n", conn_count, MAX_IP_COUNT); // 提示超过连接数 write_loop(connfd, "421 Connection refused: too many sessions for this address.\r\n", strlen("421 Connection refused: too many sessions for this address.\r\n")); continue; }else if ( (len = get_hash_length(hash_pid_ip)) >= MAX_COUNT ) { printf("超过总连接数,当前 %d 个链接\n", len); write_loop(connfd, "421 Connection refused: too many sessions\r\n", strlen("421 Connection refused: too many sessions\r\n")); } printf("---------------------------------\n"); printf("| 链接检测 |\n"); printf("| 目前同ip连接数 %2d |\n", conn_count); printf("| 总计 %2d 个链接 |\n", len); printf("---------------------------------\n"); pid = fork(); switch(pid) { case -1: exit(-1); case 0://子进程 close(listenfd); client_session(); exit(EXIT_SUCCESS); break; default: close(connfd); printf("\n新客户端接入: pid=[%d] id=[%s]\n", pid, now_ip); char str_pid[10]=""; itoa(str_pid, pid); hash_insert(hash_pid_ip, str_pid, now_ip, H_PID_IP, NULL); hash_insert(hash_ip_count, now_ip, NULL, H_IP_COUNT, NULL); int i; printf("-------------------------------------------------------\n"); for(i=0;i<HASH_MAX;i++) { if(hash_ip_count[i]!=NULL) { printf("| 客户端ip=%-20s 连接数=%-30s |\n",hash_ip_count[i]->key,hash_ip_count[i]->val); } } printf("| 总计 %2d 个链接 \n", get_hash_length(hash_pid_ip)); printf("-------------------------------------------------------\n"); break; } } }