有时候端口被不知道什么程序占用了,找不到很烦人,每次还要查询命令找进程。之前用C#实现了找出进程并且杀死的功能。这次用c实现第一个跨平台命令工具–whoport。

实现效果:
1.输入whoport提示输入要查询端口,输入端口后查询端口占用。
2."whoport 端口"直接查询跟的端口占用情况
3.“whoport -k 端口”,查询并杀死占用端口的进程

采用cmake构建工程,耗时一天,主要c操作字符串函数太弱了,测试dolerl,dolerp,dolerf几个方法画很多时间,用c写跨平台功能还是挺麻烦的,DotNetCore就容易多了。

window测试

Microsoft Windows [版本 10.0.19043.1766]
(c) Microsoft Corporation。保留所有权利。C:\WINDOWS\system32>cd C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-DebugC:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>whoport.exe -k 8082
8082占用端口进程为:iMedicalLIS监听程序.exe      26396 Console                    8     72,188 K准备杀进程C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>whoport.exe -k 8082
没有进程占用:8082端口
C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>whoport.exe -k 8082
占用端口进程为:iMedicalLIS监听程序.exe      32700 Console                    8     64,096 K准备杀进程C:\Users\zhanglianzhu\Desktop\whoport\out\build\x64-Debug>

linux测试

[root@zlzlinux whoport]# cmake /zlz/whoport/CMakeLists.txt
-- Configuring done
-- Generating done
-- Build files have been written to: /zlz/whoport
[root@zlzlinux whoport]# make
Consolidate compiler generated dependencies of target whoport
[ 33%] Building C object CMakeFiles/whoport.dir/main.c.o
[ 66%] Linking C executable whoport
[100%] Built target whoport
[root@zlzlinux whoport]# ./whoport
请输入要查看的端口:
1444
占用端口进程为:
tcp6 0 0 :::1444 :::* LISTEN 925/dotnet
[root@zlzlinux whoport]# ./whoport 1444
占用端口进程为:
tcp6 0 0 :::1444 :::* LISTEN 925/dotnet
[root@zlzlinux whoport]# ./whoport -k 1444
占用端口进程为:
tcp6 0 0 :::1444 :::* LISTEN 925/dotnet
准备杀进程
[root@zlzlinux whoport]# ./whoport --help
查看端口占用并杀死占用程序:
whoport -k port
查看端口占用:
whoport port[root@zlzlinux whoport]# 

whoport.h

//查找端口占用和杀死占用端口的程序//定义宏,防止头文件重复引用
#ifndef __WHOPORT
#define __WHOPORT
#include <stdio.h>
#include <string.h>//定义是否是Windows
#ifdef _WIN32
#include <windows.h>
//定义是否是windows
#define IsWidows 1
#else
//定义是否是windows
#define IsWidows 0
#endif/// <summary>
/// 执行命令
/// </summary>
/// <param name="cmd">命令</param>
/// <param name="result">结果</param>
/// <returns>是否成功</returns>
int ExecCmd(char* cmd, char* result);/// <summary>
/// 按分割串取长度
/// </summary>
/// <param name="source">字符串</param>
/// <param name="split">分割串</param>
/// <returns>分割的长度</returns>
int dolerl(const char* source, char* split);/// <summary>
/// 按分割串取子串
/// </summary>
/// <param name="source">字符串</param>
/// <param name="split">分割串</param>
/// <param name="index">取位数</param>
/// <param name="retStr">输出字符串</param>
/// <returns>1成功,0失败</returns>
void dolerp(char* source, char* split, int index, char* retStr);/// <summary>
/// 把多个连续字符合并为一个
/// </summary>
/// <param name="source">源串</param>
/// <param name="oneChar">要合并的字符</param>
/// <param name="retStr">输出串</param>
void MergeCharToOne(char* source, char oneChar, char* retStr);/// <summary>
/// 查找字符位置
/// </summary>
/// <param name="source">源串</param>
/// <param name="childStr">子串</param>
/// <param name="startIndex">开始位置</param>
/// <param name="findNum">查找格式</param>
/// <returns>返回位置</returns>
int dolerf(char* source, char* childStr, int startIndex, int findNum);/// <summary>
/// 通过端口找到进程号
/// </summary>
/// <param name="port">端口</param>
/// <param name="retPidArr">进程号字符串数组</param>
/// <returns>返回个数</returns>
int FindPidByPort(const char* port, char** retPidArr);/// <summary>
/// 按进程号杀进程
/// </summary>
/// <param name="count">数量</param>
/// <param name="retPidArr">进程号字符串数组</param>
int KillPid(int count, char** retPidArr);
#endif

whoport.c

#include "whoport.h"#ifdef _WIN32
/// <summary>
/// 执行命令
/// </summary>
/// <param name="cmd">命令</param>
/// <param name="result">结果</param>
/// <returns>是否成功</returns>
int ExecCmd(char* cmd, char* result)
{SECURITY_ATTRIBUTES sa;sa.nLength = sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor = NULL;sa.bInheritHandle = TRUE;HANDLE h_read, h_write;if (!CreatePipe(&h_read, &h_write, &sa, 0)){return 0;}STARTUPINFO si = { sizeof(STARTUPINFO) };GetStartupInfo(&si);si.wShowWindow = SW_HIDE;si.hStdError = NULL;si.hStdOutput = h_write;si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;PROCESS_INFORMATION pi;if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)){return -1;}CloseHandle(h_write);CloseHandle(pi.hThread);CloseHandle(pi.hProcess);DWORD i = 0, bytes_read;while (i < 2048){char buffer[1024] = { 0 };if (ReadFile(h_read, buffer, 1023, &bytes_read, NULL) == NULL){break;}strcat(result, buffer);}CloseHandle(h_read);return 1;
}
#else
/// <summary>
/// 执行命令
/// </summary>
/// <param name="cmd">命令</param>
/// <param name="result">结果</param>
/// <returns>是否成功</returns>
int ExecCmd(const char* cmd, char* result)
{FILE* pipe = popen(cmd, "r");if (!pipe){return 0;}char buffer[128] = { 0 };while (!feof(pipe)){if (fgets(buffer, 128, pipe))strcat(result, buffer);}pclose(pipe);return 1;
}
#endif/// <summary>
/// 按分割串取长度
/// </summary>
/// <param name="source">字符串</param>
/// <param name="split">分割串</param>
/// <returns>分割的长度</returns>
int dolerl(const char* source, char* split)
{int ret = 1;//源串为空返回空if (source == ""){return ret;}//分割串为空返回空if (split == ""){return ret;}int sourceLen = strlen(source);//源串为空返回空if (sourceLen == 0){return ret;}int spLen = strlen(split);//分割串为空返回空if (spLen == 0){return ret;}int curIndex = 0;int startIndex = 0;int endIndex = 0;//遍历找到按分割串分割的指定位数的串for (int i = 0; i < sourceLen; i++){//当前位置大于等于分割串长度,且当前字符等于分割串最后一位就比前面字符if (i >= spLen - 1 && source[i] == split[spLen - 1]){//时候和分割串相同int isCommon = 1;for (int j = 1; j < spLen; j++){if (source[i - j] != split[spLen - 1 - j]){isCommon = 0;break;}}if (isCommon == 1){ret++;i += spLen - 1;}}}return ret;
}/// <summary>
/// 按分割串取子串
/// </summary>
/// <param name="source">字符串</param>
/// <param name="split">分割串</param>
/// <param name="index">取位数</param>
/// <param name="retStr">输出字符串</param>
/// <returns>1成功,0失败</returns>
void dolerp(char* source, char* split, int index, char* retStr)
{//源串为空返回空if (source == ""){return;}//分割串为空返回空if (split == ""){return;}//位置不合格返回空if (index < 0){return;}int sourceLen = strlen(source);//源串为空返回空if (sourceLen == 0){return;}int spLen = strlen(split);//分割串为空返回空if (spLen == 0){return;}int curIndex = 0;int startIndex = 0;int endIndex = 0;//遍历找到按分割串分割的指定位数的串for (int i = 0; i < sourceLen; i++){//当前位置大于等于分割串长度,且当前字符等于分割串最后一位就比前面字符if (i >= spLen - 1 && source[i] == split[spLen - 1]){//是否和分割串相同int isCommon = 1;for (int j = 0; j < spLen; j++){if (source[i - j] != split[spLen - 1 - j]){isCommon = 0;break;}}if (isCommon == 1){curIndex++;if (curIndex == index + 1){endIndex = i - spLen;break;}if (curIndex == index){startIndex = i + 1;}i += spLen - 1;}}}//不包含子串返回源串if (curIndex == -1 && index == 0){strcpy(retStr, source);return;}//没有取的位数返回空else if (curIndex < index){retStr = "";return;}else{if (startIndex - endIndex == 1){retStr = "";return;}if (startIndex > endIndex){endIndex = sourceLen - 1;}int oindex = 0;for (int k = startIndex; k <= endIndex; k++){retStr[oindex] = source[k];oindex++;}retStr[oindex] = '\0';return;}
}/// <summary>
/// 把多个连续字符合并为一个
/// </summary>
/// <param name="source">源串</param>
/// <param name="oneChar">要合并的字符</param>
/// <param name="retStr">输出串</param>
void MergeCharToOne(char* source, char oneChar, char* retStr)
{//源串为空返回空if (source == ""){return;}//分割串为空返回空if (oneChar == ""){strcpy(retStr, source);return;}int len = strlen(source);char preChar;int index = 0;for (int i = 0; i < len; i++){if (i > 0 && source[i] == preChar && source[i] == oneChar){continue;}retStr[index] = source[i];index++;preChar = source[i];}retStr[index] = '\0';
}/// <summary>
/// 查找字符位置
/// </summary>
/// <param name="source">源串</param>
/// <param name="childStr">子串</param>
/// <param name="startIndex">开始位置</param>
/// <param name="findNum">查找格式</param>
/// <returns>返回位置</returns>
int dolerf(char* source, char* childStr, int startIndex, int findNum)
{//源串为空返回空if (source == ""){return -1;}//源串为空返回空if (childStr == ""){return -1;}if (findNum <= 0){return -1;}int sourceLen = strlen(source);int childLen = strlen(childStr);if (startIndex >= sourceLen){return -1;}int retIndex = -1;int curIndex = 0;for (int i = startIndex + childLen; i < sourceLen; i++){//当前位置大于等于分割串长度,且当前字符等于分割串最后一位就比前面字符if (i >= childLen && source[i] == childStr[childLen - 1]){//时候和分割串相同int isCommon = 1;for (int j = 0; j < childLen; j++){if (source[i - j] != childStr[childLen - 1 - j]){isCommon = 0;break;}}if (isCommon == 1){curIndex++;if (curIndex == findNum){retIndex = i + 1;break;}i += childLen;}}}return retIndex;
}/// <summary>
/// 通过端口找到进程号
/// </summary>
/// <param name="port">端口</param>
/// <param name="retPidArr">进程号字符串数组</param>
/// <returns>返回个数</returns>
int FindPidByPort(const char* port, char** retPidArr)
{int pidNum = 0;//windows执行指令if (IsWidows == 1){char* result[1024 * 10] = { 0 };//执行命令行int ret = ExecCmd("netstat -ano", result);//得到分割长度int len = dolerl(result, "\r\n");//遍历每行数据for (int i = 0; i < len; i++){char oneLine[1024] = { 0 };//分割得到对应行数据dolerp(result, "\r\n", i, oneLine);//判断包含端口if (dolerf(oneLine, port, 0, 1) > -1){char oneLineMerge[1024] = { 0 };//合并多个连续空格MergeCharToOne(oneLine, ' ', oneLineMerge);//得到一行的按空格分割列int spLen = dolerl(oneLineMerge, " ");//是要的数据if (spLen > 5){char flag[1024];char ipPort[20] = "0.0.0.0:";strcat(ipPort, port);char ipPort1[20] = "127.0.0.1:";strcat(ipPort1, port);dolerp(oneLineMerge, " ", 2, flag);if (strcmp(flag, ipPort) == 0 || strcmp(flag, ipPort1) == 0){//把pid取到返回数组dolerp(oneLineMerge, " ", 5, retPidArr[pidNum]);pidNum++;char getexeNameCmd[50] = "tasklist /NH /FI \"PID eq ";strcat(getexeNameCmd, retPidArr[pidNum]);strcat(getexeNameCmd, "\"");char exeInfo[1024 * 20] = { 0 };//执行命令行int ret = ExecCmd(getexeNameCmd, exeInfo);printf("%s\n", "占用端口进程为:");printf("%s\n", exeInfo);}}}}return pidNum;}//linuxelse{char* result[1024 * 100] = { 0 };//执行命令行int ret = ExecCmd("netstat -tunlp", result);//得到分割长度int len = dolerl(result, "\n");//遍历每行数据for (int i = 0; i < len; i++){char oneLine[1024] = { 0 };//分割得到对应行数据dolerp(result, "\n", i, oneLine);//判断包含端口if (dolerf(oneLine, port, 0, 1) > -1){char oneLineMerge[1024] = { 0 };//合并多个连续空格MergeCharToOne(oneLine, ' ', oneLineMerge);//得到一行的按空格分割列int spLen = dolerl(oneLineMerge, " ");//是要的数据if (spLen > 7){char flag[1024];char ipPort[20] = ":::";strcat(ipPort, port);char ipPort1[20] = "127.0.0.1:";strcat(ipPort1, port);dolerp(oneLineMerge, " ", 3, flag);if (strcmp(flag, ipPort) == 0 || strcmp(flag, ipPort1) == 0){char tmp[100];//把pid取到返回数组dolerp(oneLineMerge, " ", 6, tmp);dolerp(tmp, "/", 0, retPidArr[pidNum]);pidNum++;printf("%s\n", "占用端口进程为:");printf("%s\n", oneLineMerge);}}}}return pidNum;}
}/// <summary>
/// 按进程号杀进程
/// </summary>
/// <param name="count">数量</param>
/// <param name="retPidArr">进程号字符串数组</param>
int KillPid(int count, char** retPidArr)
{//windows执行指令if (IsWidows == 1){for (int i = 0; i < count; i++){char* result[1024] = { 0 };char cmd[50] = "taskkill /pid ";strcat(cmd, retPidArr[i]);strcat(cmd, " -t -f");//执行命令行int ret = ExecCmd(cmd, result);return ret;}}else{for (int i = 0; i < count; i++){char* result[1024] = { 0 };char cmd[50] = "kill -9 ";strcat(cmd, retPidArr[i]);//执行命令行int ret = ExecCmd(cmd, result);return ret;}}return 0;
}

main.c

#include "whoport.h"/// <summary>
/// 入口
/// </summary>
/// <param name="count">参数个数</param>
/// <param name="args">参数</param>
/// <returns>返回</returns>
int main(int count, char* args[])
{//端口char portArr[10];//没传参数,提示输入端口if (count == 1){printf("请输入要查看的端口:\n");scanf("%s", &portArr);}//有两个参数就认为传的端口else if (count == 2){//帮助if (strcmp(args[1], "--help") == 0){printf("%s\n", "查看端口占用并杀死占用程序:");printf("%s\n","whoport -k port");printf("%s\n", "查看端口占用:");printf("%s\n", "whoport port");return 0;}strcpy(portArr, args[1]);}//有三个参数就认为第三个传的端口else if (count == 3){strcpy(portArr, args[2]);}//放查找的pdfchar* pidArr[30];for (int i = 0; i < 20; i++){char tmp[10];pidArr[i] = tmp;}//查找端口占用int num = FindPidByPort(portArr, pidArr);//杀进程if (count >= 3 && strcmp(args[1], "-k") == 0){//有占用的就杀进程if (num > 0){printf("%s\n","准备杀进程");KillPid(num, pidArr);}else{printf("没有进程占用:%s端口", portArr);}}return 0;
}

CMakeLists.txt

# CMakeList.txt: whoport 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)project ("whoport")# 将源代码添加到此项目的可执行文件。
add_executable (whoport "whoport.c" "whoport.h" "main.c")# TODO: 如有需要,请添加测试并安装目标。

第一个C跨平台工具whoport相关推荐

  1. 跨平台工具、组件和框架的汇总

    本文主要是对跨平台工具.组件和框架的汇总,包括游戏引擎.编程语言.移动开发.网络通信.图形界面等等 Qt是1991年奇趣科技开发的一个跨平台的C++图形用户界面应用程序框架.它提供给应用程序开发者建立 ...

  2. 从 1 到完美,用 node 写一个命令行工具

    从 1 到完美,用 node 写一个命令行工具 1. package.json 中的 bin 字段 现在,不管是前端项目还是 node 项目,一般都会用 npm 做包管理工具,而 package.js ...

  3. 跨平台工具详解:Netbiscuits (Kony solutions的竞争对手)

    Netbiscuits公司成立于2000年,最初是一个WAP门户网站的开发机构,后来在2007年转向跨平台工具(CPT)领域.该公司位于德国的Kaiserlautern,在全世界拥有8个旗下分支工作室 ...

  4. μthenticode:一款用于验证 Windows 文件签名的跨平台工具

    μthenticode:一款用于验证 Windows 文件签名的跨平台工具,用于在没有Windows设备的情况下在Windows PE二进制文件上验证Authenticode签名.开发人员还将其集成到 ...

  5. Wifitap是一个WiFi注入工具集常用命令集合大学霸IT达人

    Wifitap是一个WiFi注入工具集常用命令集合大学霸IT达人 该工具集允许任何应用程序都可以发送和接收IP数据包,使用802.11流量捕获和注入,并通过WiFi网络简单配置接口wj0.Wifita ...

  6. Apache中的一个测试小工具

    一个不错的 目录中的 ab.exe ,相当简单容易的一个测试小工具. ab -n 1000 -c 50 http://www.xxx.com/(要测试的网站目录)相当的简单容易.让你初步对服务器的性能 ...

  7. 第三方模块——nodemon是一个命令行工具,用以辅助项目开发、nrm ( npm registry manager ):npm下载地址切换工具

    什么是第三方模块 别人写好的.具有特定功能的.我们能直接使用的模块即第三方模块,由于第三方模块通常都是由多个文件组成并且被放置在一个文件夹中,所以又名包. 第三方模块 nodemon nodemon是 ...

  8. 怎么看承重_怎么选购到一个好的工具柜,这些方面要考虑

    作为正常工序的重要组成部分,工具柜适用于工具.刀具.零部件在生产现场中的定制管理,使工人在物品存取工作时更加高效.便利.而作为工厂,生产安全必须是第一位的,因此选择可靠的承重型工具柜就显得尤为重要.今 ...

  9. gorm存指针数据_gormt: gormt 是一个数据库映射工具,可以将 mysql 数据库自动生成 golang sturct 结构...

    mysql数据库转 struct 工具,可以将mysql数据库自动生成golang sturct结构,带大驼峰命名规则.带json标签 交互界面模式 ./gormt -g=true 命令行模式 ./g ...

最新文章

  1. 起底车载互联市场:产业市场庞大,但产品鱼龙混杂
  2. Redis:相关知识点纵观
  3. ML之SVM(三种):基于三种SVM(linearSVR、polySVR、RBFSVR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能
  4. How to be a hacker
  5. C语言3中方法判断32还是64位机
  6. 【Solidity】1.一个Solidity源文件的布局 - 深入理解Solidity
  7. JavaScript学习笔记:常量,枚举,宏定义
  8. Vue事件处理_vue的事件处理超级方便_功能强大---vue工作笔记0011
  9. 6个座位办公室最佳位置_办公室座位最佳位置(讲解)
  10. 威联通 Qnap PK 群晖 Synology 安全篇3
  11. DDD领域建模基本流程
  12. java 文本编码_Java文件编码
  13. 分享一个MAC下绕开百度网盘限速下载的方法,三步操作永久生效
  14. 最值得收藏的 搜狗输入法 常用快捷键使用, 让你的效率成倍增加
  15. 视觉-摄像机3】}摄像机镜头--焦距与视角(选相机和镜头)
  16. OpenAI生成二次元美女【辣眼睛慎入】
  17. OCAD应用:光楔初始设计
  18. 发布制品到 Jfrog Artifactory
  19. java 坦克世界源代码教程_译文教程:坦克世界游戏制作技术分享
  20. java服务内存占用过高

热门文章

  1. 手机数据恢复软件怎么选择
  2. 小虎电商浏览器:多多打单怎么关联多家店铺打单
  3. 软件测试(基础知识)
  4. 【愚公系列】2022年10月 微信小程序-电商项目-微信支付后端功能实现(node版)
  5. SAP 教程之 05 如何创建 IDOC 基本类型文档?
  6. 今日份PS练习|灯照效果
  7. 酒店无线覆盖-工业级无线AP
  8. 固态硬盘和机械硬盘区别
  9. 关于u盘启动,关于UEFI,关于hp手提计算机
  10. 美国西北大学新系统在智力测试中超越75%民众,人类的推理能力也不及AI了?...