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