linux实现tcp工具

之前实现的whoport工具实现了linux和windows通用的端口占用查找工具。这次基于之前基础实现tcp工具。其中就包含启动tcp服务端和启动tcp客户端功能。为啥要闲的蛋疼干这个呢?

这不是以后都用linux了嘛。以前用windows时候还有能用“SocketTool.exe”测试tcp连接。碰到蛋疼的网络杀长连接问题时候在服务器开个tcp服务,在客户端开个tcp客户端,看一段时间连接是不是会被杀掉。换到linux后前段时间我也碰到这种蛋疼的网络问题了。然后就得各种程序证明这个问题是网络问题不是程序问题。发现没合适的在linux启动tcp客户端和服务端工具。为此拿来做c语言练习题了。

实现目标:
1.在linux指定端口开启tcp服务侦听,能收到客户端连接和发来的消息。能人工敲消息发送个所有连接的客户端。
2.在linux指定服务端IP和端口连接上去,能收服务端发来的消息。能人工给服务端发消息。

支持的命令如下:

#开启tcp服务端口侦听
whoport -s port
#开启tcp客户端连接
whoport -c ip port
#查看端口占用并杀死占用程序
whoport -k port
#查看端口占用
whoport port

源码下载地址

工程采用cmake开发,CMakeList.txt如下,因为用到了线程,所以需要给cmake加上c语言线程编译的连接信息-pthread。cmake加-pthread的问题花了些时间

# CMakeList.txt: whoport 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)

project ("whoport")



# 将源代码添加到此项目的可执行文件。
add_executable (whoport "whoport.c" "whoport.h" "httpclient.c" "httpclient.h" "httpserver.c" "httpserver.h" "main.c")

#引入编译线程的标识,否则编译线程会报错
SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-pthread")
# TODO: 如有需要,请添加测试并安装目标。

服务端实现:
httpclient.h

//定义宏,防止头文件重复引用
#ifndef __HTTPSERVER
#define __HTTPSERVER
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/// 
/// 结构体
/// 
struct  TcpClient
{
	int sockfd;
	struct TcpClient* preClient;
	struct TcpClient* nextClient
};
//客户端链表
extern struct TcpClient* ClientPointer;

/// 
/// 到指定端口打开tcp服务
/// 
/// 端口
/// 服务句柄
int OpenServer(int port);

/// 
/// 给所有客户端发消息
/// 
/// 
void SenMsgToAllClient(char* msg);

/// 
/// 关闭指定服务
/// 
/// 服务句柄
/// 
int CloseServer(int serverHandler);


#endif

httpserver.c

#include "httpserver.h"

/// 
/// 添加客户端
/// 
/// 
void AddClient(struct TcpClient* clientStruct);

/// 
/// 移除客户端
/// 
/// 
void RemoveClient(struct TcpClient* clientStruct);

/// 
/// 接收客户端发来的数据
/// 
/// 客户端句柄
void AcceptClienData(int client);

/// 
/// 侦听客户端的连接
/// 
/// 
void ListenClienConnect(int sockfd);

/// 
/// 客户端链表
/// 
struct TcpClient* ClientPointer = NULL;


/// 
/// 到指定端口打开tcp服务
/// 
/// 端口
/// 服务句柄
int OpenServer(int port)
{
	//创建套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sockfd == -1)
	{
		perror("sockfd failed!\n");
		return 0;
	}

	//绑定端口
	struct sockaddr_in serv_addr;
	memset(&serv_addr, 0, sizeof(serv_addr));
	//套接字对象
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
	serv_addr.sin_port = htons(port);
	//绑定套接字与端口
	bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
	printf("侦听端口:%d\n", port);
	//服务端开始监听
	int ret = listen(sockfd, 20);
	if (ret == -1) {
		printf("侦听失败");
	}
	pthread_t newthread;
	int threadRet = pthread_create(&newthread, NULL, ListenClienConnect, sockfd);
	if (threadRet == 0)
	{
	}
	else
	{
		printf("-1^创建线程侦听客户端失败:%d", threadRet);
	}
	//返回服务句柄
	return sockfd;
}

/// 
/// 关闭指定服务
/// 
/// 服务句柄
/// 成功返回0
int CloseServer(int serverHandler)
{
	int ret = close(serverHandler);
	return 0;
}

/// 
/// 侦听客户端的连接
/// 
/// 
void ListenClienConnect(int sockfd)
{
	while (1)
	{
		printf("正在侦听客户端连接...\n");
		//连接客户端:接受来自客户端发起的连接
		struct sockaddr_in clientAddr;
		socklen_t cLen = sizeof(clientAddr);
		int connect_sockfd = accept(sockfd, (struct sockaddr*)&clientAddr, &cLen);
		if (connect_sockfd == -1)
		{
			printf("-1^客户端连接失败!\n");
			continue;
		}
		char* clientIP = inet_ntoa(clientAddr.sin_addr);
		int clientPort = ntohs(clientAddr.sin_port);
		printf("C->S# 客户端IP:%s:%d连入\n", clientIP, clientPort);
		pthread_t newthread;
		if (pthread_create(&newthread, NULL, AcceptClienData, connect_sockfd) == 0)
		{
		}
		else
		{
			printf("-1^创建线程接收客户端数据失败!");
		}
	}
}

/// 
/// 接收客户端发来的数据
/// 
/// 客户端句柄
void AcceptClienData(int client)
{
	//收发数据
	char recvBuf[1024] = { 0 };
	struct TcpClient clientStruct;
	clientStruct.sockfd = client;
	//加入客户端链表
	AddClient(&clientStruct);
	char *head = "服务端收到:";
	//死循环接收数据
	while (1)
	{
		//清空之后再接收数据
		memset(recvBuf, 0, sizeof(recvBuf));
		int recvbytes = recv(client, recvBuf, sizeof(recvBuf), 0);
		if (recvbytes == -1)
		{
			printf("-1^接收客户端数据异常");
			break;
		}
		printf("C->S# %s\n", recvBuf);
		//发说明
		write(client, head, strlen(head));
		write(client, recvBuf, sizeof(recvBuf));
	}
	//从客户端链表移除
	RemoveClient(&clientStruct);
}

/// 
/// 添加客户端
/// 
/// 
void AddClient(struct TcpClient* clientStruct)
{
	clientStruct->nextClient = NULL;
	clientStruct->preClient = NULL;
	if (ClientPointer == NULL)
	{
		ClientPointer = clientStruct;
	}
	else
	{
		clientStruct->nextClient = ClientPointer;
		ClientPointer->preClient = clientStruct;
		ClientPointer = clientStruct;
	}
}

/// 
/// 移除客户端
/// 
/// 
void RemoveClient(struct TcpClient* clientStruct)
{
	//只一个客户端
	if (clientStruct->preClient == NULL && clientStruct->nextClient == NULL)
	{
		ClientPointer = NULL;
	}
	//第一个元素
	else if (clientStruct->preClient == NULL && clientStruct->nextClient != NULL)
	{
		ClientPointer = clientStruct->nextClient;
	}
	//最后一个元素
	else if (clientStruct->preClient != NULL && clientStruct->nextClient == NULL)
	{
		clientStruct->preClient->nextClient = NULL;
	}
	//中间元素
	else
	{
		clientStruct->preClient->nextClient = clientStruct->nextClient;
	}
}

/// 
/// 给所有客户端发消息
/// 
/// 
void SenMsgToAllClient(char* msg)
{
	//输出日志
	printf("S->C# %s\n", msg);
	if (ClientPointer != NULL)
	{
		struct TcpClient* clientTmp;
		clientTmp = ClientPointer;
		write(clientTmp->sockfd, msg, sizeof(msg));
		while (clientTmp->nextClient != NULL)
		{
			clientTmp = clientTmp->nextClient;
			write(clientTmp->sockfd, msg, sizeof(msg));
		}
	}
}

客户端实现:
httpclient.h

#ifndef __HTTPCLIENT
#define __HTTPCLIENT

#include 
#include 
#include 
#include 
#include 
#include 
#include 

/// 
/// 连接服务
/// 
/// 服务ip地址
/// 服务端口
/// 返回客户端句柄
int ConnectServer(char* ipStr, int port);

/// 
/// 关闭客户端
/// 
/// 客户端句柄
/// 
int CloseClient(int clientHandler);

/// 
/// 给服务端发消息
/// 
/// 客户端句柄
/// 消息
void SenMsgToAllServer(int clientHandler, char* msg);

#endif

httpclient.c

#include "httpclient.h"

/// 
/// 接收服务端发来的数据
/// 
/// 
void RecieveServerData(int sockfd);

/// 
/// 连接服务
/// 
/// 服务ip地址
/// 服务端口
/// 返回客户端句柄
int ConnectServer(char* ipStr, int port)
{
	//创建一个套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1)
	{
		printf("创建套接字失败!\n");
		return 0;
	}
	//连接服务端
	struct sockaddr_in servAddr;
	//套接字对象
	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	//服务端地址
	servAddr.sin_addr.s_addr = inet_addr(ipStr);
	servAddr.sin_port = htons(port);
	int len = sizeof(servAddr);
	//连接服务端
	int connRet = connect(sockfd, (struct sockaddr*)&servAddr, len);
	if (connRet == -1)
	{
		printf("连接服务器%s:%d失败,返回:%d\n", ipStr, port, connRet);
		exit(1);
	}
	printf("连接服务器%s:%d返回:%d\n", ipStr, port, connRet);
	pthread_t newthread;
	if (pthread_create(&newthread, NULL, RecieveServerData, sockfd) == 0)
	{
	}
	else
	{
		printf("-1^创建线程接收客户端数据失败!");
	}
	return sockfd;
}

/// 
/// 接收服务端发来的数据
/// 
/// 
void RecieveServerData(int sockfd)
{
	//收发数据
	char recvBuf[1024] = { 0 };
	printf("接收服务器数据中...\n");
	while (1)
	{
		//清空之后再接收数据
		memset(recvBuf, 0, sizeof(recvBuf));
		//接收数据
		read(sockfd, recvBuf, sizeof(recvBuf) - 1);
		if (strlen(recvBuf) != 0)
		{
			printf("S->C# %s\n", recvBuf);
		}
		if (strcmp(recvBuf, "eot") == 0)
		{
			printf("退出连接...\n");
			break;
		}
	}
}

/// 
/// 关闭客户端
/// 
/// 客户端句柄
/// 
int CloseClient(int clientHandler)
{
	//关闭套接字
	int ret = close(clientHandler);
}

/// 
/// 给服务端发消息
/// 
/// 客户端句柄
/// 消息
void SenMsgToAllServer(int clientHandler, char* msg)
{
	printf("C->S# %s\n", msg);
	int ret = write(clientHandler, msg, strlen(msg));
}

主方法:
main.c

#include "whoport.h"
#include "httpclient.h"
#include "httpserver.h"

/// 
/// 入口
/// 
/// 参数个数
/// 参数
/// 返回
int main(int count, char* args[])
{
	//4个参数判断是不是开启客户端命令
	if (count == 4)
	{
		//tcp客户端
		if (strcmp(args[1], "-c") == 0)
		{
			int port;
			//转换端口
			sscanf(args[3], "%d", &port);
			//连接到服务端
			int clientHandler = ConnectServer(args[2], port);
			//连接成功了开启死循环让用户录入数据
			if (clientHandler > 0)
			{
				//稍微等待一秒
				usleep(1000);
				char inputStr[10000];
				while (1)
				{
					//清空数组
					memset(inputStr, 0, sizeof(inputStr));
					//输出提示
					printf("请输入要发送给服务端的数据(输入eot结束连接):\n");
					//读取键盘
					scanf("%s", &inputStr);
					//检测是否退出
					if (strcmp(inputStr, "eot") == 0)
					{
						printf("退出连接...\n");
						break;
					}
					//发送给服务端
					SenMsgToAllServer(clientHandler, inputStr);
				}
				//关闭客户端
				CloseClient(clientHandler);
			}
			return 0;
		}
	}
	//三个参数时候判断是不是tcp服务端命令
	if (count == 3)
	{
		//tcp服务端
		if (strcmp(args[1], "-s") == 0)
		{
			int port;
			//转换端口
			sscanf(args[2], "%d", &port);
			//开启服务
			int serverHandler = OpenServer(port);
			//启动成功了开始是循环让用户能输入数据
			if (serverHandler > 0)
			{
				//稍微等待一秒
				usleep(1000);
				char inputStr[10000];
				while (1)
				{
					//情况数组
					memset(inputStr, 0, sizeof(inputStr));
					printf("请输入要发送给客户端的数据(输入eot结束服务):\n");
					//捕获键盘
					scanf("%s", &inputStr);
					if (strcmp(inputStr, "eot") == 0)
					{
						printf("退出服务...\n");
						break;
					}
					//发送给所有客户端
					SenMsgToAllClient(inputStr);
				}
				//关闭服务
				CloseServer(serverHandler);
			}
			return 0;
		}
	}
	//端口
	char portArr[10];
	//没传参数,提示输入端口
	if (count == 1)
	{
		printf("请输入要查看的端口:\n");
		scanf("%s", &portArr);
	}
	//有两个参数就认为传的端口
	else if (count == 2)
	{
		//帮助
		if (strcmp(args[1], "--help") == 0)
		{
			printf("%s\n\n", "使用帮助如下:");
			printf("%s\n", "开启tcp服务端口侦听:");
			printf("%s\n", "whoport -s port");
			printf("%s\n", "开启tcp客户端连接:");
			printf("%s\n", "whoport -c ip port");
			printf("%s\n", "查看端口占用并杀死占用程序:");
			printf("%s\n", "whoport -k port");
			printf("%s\n", "查看端口占用:");
			printf("%s\n", "whoport port");
			printf("\n\n\n");
			return 0;
		}
		strcpy(portArr, args[1]);
	}
	//有三个参数就认为第三个传的端口
	else if (count == 3)
	{
		strcpy(portArr, args[2]);
	}
	//放查找的pdf
	char* 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;
}

编译:

[root@zlzlinux whoport]# 
[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
[100%] Built target whoport
[root@zlzlinux whoport]# make
[100%] Built target whoport
[root@zlzlinux whoport]# make clean
[root@zlzlinux whoport]# make
[ 20%] Building C object CMakeFiles/whoport.dir/whoport.c.o
/zlz/whoport/whoport.c: 在函数‘MergeCharToOne’中:
/zlz/whoport/whoport.c:256:14: 警告:比较指针和整数
  if (oneChar == "")
              ^~
/zlz/whoport/whoport.c: 在函数‘FindPidByPort’中:
/zlz/whoport/whoport.c:355:37: 警告:传递‘ExecCmd’的第 2 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
   int ret = ExecCmd("netstat -ano", result);
                                     ^~~~~~
/zlz/whoport/whoport.c:56:30: 附注:需要类型‘char *’,但实参的类型为‘char **’
 int ExecCmd(char* cmd, char* result)
                        ~~~~~~^~~~~~
/zlz/whoport/whoport.c:357:20: 警告:传递‘dolerl’的第 1 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
   int len = dolerl(result, "\r\n");
                    ^~~~~~
/zlz/whoport/whoport.c:80:24: 附注:需要类型‘const char *’,但实参的类型为‘char **’
 int dolerl(const char* source, char* split)
            ~~~~~~~~~~~~^~~~~~
/zlz/whoport/whoport.c:363:11: 警告:传递‘dolerp’的第 1 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
    dolerp(result, "\r\n", i, oneLine);
           ^~~~~~
/zlz/whoport/whoport.c:143:19: 附注:需要类型‘char *’,但实参的类型为‘char **’
 void dolerp(char* source, char* split, int index, char* retStr)
             ~~~~~~^~~~~~
/zlz/whoport/whoport.c:365:24: 警告:passing argument 2 of ‘dolerf’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    if (dolerf(oneLine, port, 0, 1) > -1)
                        ^~~~
/zlz/whoport/whoport.c:285:32: 附注:需要类型‘char *’,但实参的类型为‘const char *’
 int dolerf(char* source, char* childStr, int startIndex, int findNum)
                          ~~~~~~^~~~~~~~
/zlz/whoport/whoport.c:407:39: 警告:传递‘ExecCmd’的第 2 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
   int ret = ExecCmd("netstat -tunlp", result);
                                       ^~~~~~
/zlz/whoport/whoport.c:56:30: 附注:需要类型‘char *’,但实参的类型为‘char **’
 int ExecCmd(char* cmd, char* result)
                        ~~~~~~^~~~~~
/zlz/whoport/whoport.c:409:20: 警告:传递‘dolerl’的第 1 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
   int len = dolerl(result, "\n");
                    ^~~~~~
/zlz/whoport/whoport.c:80:24: 附注:需要类型‘const char *’,但实参的类型为‘char **’
 int dolerl(const char* source, char* split)
            ~~~~~~~~~~~~^~~~~~
/zlz/whoport/whoport.c:415:11: 警告:传递‘dolerp’的第 1 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
    dolerp(result, "\n", i, oneLine);
           ^~~~~~
/zlz/whoport/whoport.c:143:19: 附注:需要类型‘char *’,但实参的类型为‘char **’
 void dolerp(char* source, char* split, int index, char* retStr)
             ~~~~~~^~~~~~
/zlz/whoport/whoport.c:417:24: 警告:passing argument 2 of ‘dolerf’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    if (dolerf(oneLine, port, 0, 1) > -1)
                        ^~~~
/zlz/whoport/whoport.c:285:32: 附注:需要类型‘char *’,但实参的类型为‘const char *’
 int dolerf(char* source, char* childStr, int startIndex, int findNum)
                          ~~~~~~^~~~~~~~
/zlz/whoport/whoport.c: 在函数‘KillPid’中:
/zlz/whoport/whoport.c:469:27: 警告:传递‘ExecCmd’的第 2 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
    int ret = ExecCmd(cmd, result);
                           ^~~~~~
/zlz/whoport/whoport.c:56:30: 附注:需要类型‘char *’,但实参的类型为‘char **’
 int ExecCmd(char* cmd, char* result)
                        ~~~~~~^~~~~~
/zlz/whoport/whoport.c:482:27: 警告:传递‘ExecCmd’的第 2 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
    int ret = ExecCmd(cmd, result);
                           ^~~~~~
/zlz/whoport/whoport.c:56:30: 附注:需要类型‘char *’,但实参的类型为‘char **’
 int ExecCmd(char* cmd, char* result)
                        ~~~~~~^~~~~~
[ 40%] Building C object CMakeFiles/whoport.dir/httpclient.c.o
/zlz/whoport/httpclient.c: 在函数‘ConnectServer’中:
/zlz/whoport/httpclient.c:42:39: 警告:传递‘pthread_create’的第 3 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
  if (pthread_create(&newthread, NULL, RecieveServerData, sockfd) == 0)
                                       ^~~~~~~~~~~~~~~~~
In file included from /zlz/whoport/httpclient.h:10,
                 from /zlz/whoport/httpclient.c:1:
/usr/include/pthread.h:236:15: 附注:需要类型‘void * (*)(void *)’,但实参的类型为‘void (*)(int)’
       void *(*__start_routine) (void *),
       ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/zlz/whoport/httpclient.c:42:58: 警告:传递‘pthread_create’的第 4 个参数时将整数赋给指针,未作类型转换 [-Wint-conversion]
  if (pthread_create(&newthread, NULL, RecieveServerData, sockfd) == 0)
                                                          ^~~~~~
In file included from /zlz/whoport/httpclient.h:10,
                 from /zlz/whoport/httpclient.c:1:
/usr/include/pthread.h:237:24: 附注:需要类型‘void * restrict’,但实参的类型为‘int’
       void *__restrict __arg) __THROWNL __nonnull ((1, 3));
       ~~~~~~~~~~~~~~~~~^~~~~
[ 60%] Building C object CMakeFiles/whoport.dir/httpserver.c.o
In file included from /zlz/whoport/httpserver.c:1:
/zlz/whoport/httpserver.h:21:1: 警告:结构或联合后没有分号
 };
 ^
/zlz/whoport/httpserver.c: 在函数‘OpenServer’中:
/zlz/whoport/httpserver.c:64:51: 警告:传递‘pthread_create’的第 3 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
  int threadRet = pthread_create(&newthread, NULL, ListenClienConnect, sockfd);
                                                   ^~~~~~~~~~~~~~~~~~
In file included from /zlz/whoport/httpserver.h:11,
                 from /zlz/whoport/httpserver.c:1:
/usr/include/pthread.h:236:15: 附注:需要类型‘void * (*)(void *)’,但实参的类型为‘void (*)(int)’
       void *(*__start_routine) (void *),
       ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/zlz/whoport/httpserver.c:64:71: 警告:传递‘pthread_create’的第 4 个参数时将整数赋给指针,未作类型转换 [-Wint-conversion]
  int threadRet = pthread_create(&newthread, NULL, ListenClienConnect, sockfd);
                                                                       ^~~~~~
In file included from /zlz/whoport/httpserver.h:11,
                 from /zlz/whoport/httpserver.c:1:
/usr/include/pthread.h:237:24: 附注:需要类型‘void * restrict’,但实参的类型为‘int’
       void *__restrict __arg) __THROWNL __nonnull ((1, 3));
       ~~~~~~~~~~~~~~~~~^~~~~
/zlz/whoport/httpserver.c: 在函数‘ListenClienConnect’中:
/zlz/whoport/httpserver.c:109:40: 警告:传递‘pthread_create’的第 3 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
   if (pthread_create(&newthread, NULL, AcceptClienData, connect_sockfd) == 0)
                                        ^~~~~~~~~~~~~~~
In file included from /zlz/whoport/httpserver.h:11,
                 from /zlz/whoport/httpserver.c:1:
/usr/include/pthread.h:236:15: 附注:需要类型‘void * (*)(void *)’,但实参的类型为‘void (*)(int)’
       void *(*__start_routine) (void *),
       ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/zlz/whoport/httpserver.c:109:57: 警告:传递‘pthread_create’的第 4 个参数时将整数赋给指针,未作类型转换 [-Wint-conversion]
   if (pthread_create(&newthread, NULL, AcceptClienData, connect_sockfd) == 0)
                                                         ^~~~~~~~~~~~~~
In file included from /zlz/whoport/httpserver.h:11,
                 from /zlz/whoport/httpserver.c:1:
/usr/include/pthread.h:237:24: 附注:需要类型‘void * restrict’,但实参的类型为‘int’
       void *__restrict __arg) __THROWNL __nonnull ((1, 3));
       ~~~~~~~~~~~~~~~~~^~~~~
[ 80%] Building C object CMakeFiles/whoport.dir/main.c.o
In file included from /zlz/whoport/main.c:3:
/zlz/whoport/httpserver.h:21:1: 警告:结构或联合后没有分号
 };
 ^
[100%] Linking C executable whoport
[100%] Built target whoport
[root@zlzlinux whoport]# ls
CMakeCache.txt  cmake_install.cmake  httpclient.c  httpserver.c  main.c    out      whoport.c
CMakeFiles      CMakeLists.txt       httpclient.h  httpserver.h  Makefile  whoport  whoport.h
[root@zlzlinux whoport]# 

测试:
服务端

[root@zlzlinux whoport]# 
[root@zlzlinux whoport]# ./whoport -s 5003
侦听端口:5003
正在侦听客户端连接...
请输入要发送给客户端的数据(输入eot结束服务):
C->S# 客户端IP:192.168.0.104:51336连入
正在侦听客户端连接...
C->S# 我是张珊
C->S# 我是zlz

客户端

[root@zlzlinux whoport]# 
[root@zlzlinux whoport]# 
[root@zlzlinux whoport]# ./whoport -c 192.168.0.104 5003
连接服务器192.168.0.104:5003返回:0
接收服务器数据中...
请输入要发送给服务端的数据(输入eot结束连接):
我是张珊
C->S# 我是张珊
请输入要发送给服务端的数据(输入eot结束连接):
S->C# 服务端收到:我是张珊
我是zlz
C->S# 我是zlz
请输入要发送给服务端的数据(输入eot结束连接):
S->C# 服务端收到:
S->C# 我是zlz

混合测试:
linux实现tcp工具_第1张图片
linux实现tcp工具_第2张图片

多个客户端测试:
linux实现tcp工具_第3张图片
linux实现tcp工具_第4张图片

以上就是tcp服务端和客户端的实现小工具。中文还有点乱码的问题后面再看。后期可以并入imedicallis命令的体系里去,哈哈。

你可能感兴趣的:(c,linux,TCP,linux,tcp/ip,网络)