控制台命令状态运行的TCP通信服务器及客户机程序,实现简单的数据传输功能
采用vs2019控制台应用实现
客户机部分
//客户机main函数
#include <stdio.h>
#include "CComm.h"
int main(int argc, char* argv[])
{
char buffer[4096]; //输入缓冲区
char* desthost; //服务器ip地址
short destport; // 服务器端口号
// 确保输入正确
if (argc != 3 || !(destport = atoi(argv[2])) || !(desthost = argv[1]))
{
printf("输入正确的服务器IP地址和端口号\n");
return 0;
}
CComm myComm;
if (!myComm.Listen(desthost,destport)) // 连接到服务器地址
{
printf("连接失败\n");
return 0;
}
while (fgets(buffer, sizeof(buffer), stdin)) // 获得输入数据
{
myComm.SendMsg(buffer, strlen(buffer)); // 发送数据到服务器
}
return 0;
}
//CComm.h
#pragma once
#include <string.h>
#include<stdio.h>
#include<stdlib.h>
#include<winsock.h>
#define socklen_t int;
#pragma comment(lib,"wsock32.lib")
class CComm
{
private:
static void* ListenThread(void* data);
SOCKET ClientSocket; //等待接收数据的socket
sockaddr_in srv; //绑定地址
public:
CComm();
~CComm();
bool Listen(char * addr,int PortNum);
bool SendMsg(char* Msg, int Len);
};
//CComm.cpp
#include "CComm.h"
CComm::CComm()
{
//构造函数
ClientSocket = INVALID_SOCKET; // 开始设置为INVALID_SOCKET
#ifdef _WIN32 // 如果是win32系统
WORD VersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(VersionRequested, &wsaData); // 启动winsock服务
if (wsaData.wVersion != VersionRequested)
{
printf("Wrong version or WinSock not loaded\n");
fflush(0);
}
#endif
}
CComm::~CComm()
{//析构函数
if (ClientSocket != INVALID_SOCKET)
closesocket(ClientSocket); // 如果已经创建、则关闭
#ifdef _WIN32 // 调用WSACleanup
WSACleanup();
#endif
}
bool CComm::SendMsg(char* Msg, int Len)//向服务器发送数据
{
signed int Sent;
Sent = send(ClientSocket, Msg, Len, 0);
if (Sent != Len)
{
printf("发送失败 \n");
fflush(0);
return false;
}
return true;
}
bool CComm::Listen(char* addr,int PortNum)
{
ClientSocket = socket(PF_INET, SOCK_STREAM, 0);
if (ClientSocket == INVALID_SOCKET)
{
printf("socket创建失败\n");
fflush(0);
return false;
}
srv.sin_family = PF_INET;
srv.sin_addr.S_un.S_addr= inet_addr(addr);//TCP客户端需要有确切的地址
srv.sin_port = htons(PortNum);//字节顺序转换
if (connect(ClientSocket, (struct sockaddr*) &srv, sizeof(sockaddr)) != 0)
{
printf("连接失败\n");
fflush(0);
closesocket(ClientSocket);
return false;
}
else {
char sendbuf[1024],hostname[100];
gethostname(hostname,100);//获得主机名称
sprintf_s(sendbuf, "%s 已连接!", hostname);
send(ClientSocket, sendbuf, strlen(sendbuf) + 1, 0);
}
int ThreadID; // 线程id
DWORD thread;
//调用createthread创建线程
ThreadID = (int)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(CComm::ListenThread), (void*)this, 0, &thread);
ThreadID = ThreadID ? 0 : 1; // 如果成功,则返回为0
if (ThreadID) // ThreadID如果不为0,则线程创建失败
{
printf("线程创建失败\n");
return false;
}
else
return true;
}
void* CComm::ListenThread(void* data)
{
char buf[4096];
CComm* Comm = (CComm*)data;
bool flag = true;
while (1) // 一直循环
{
//接收数据
int result = recv(Comm->ClientSocket, buf, sizeof(buf) - 1, 0);
if (result > 0)
{
buf[result] = 0;
if (flag) {
printf("%s \n", buf);
flag = false;
}
else{
printf("Message received from host %s port %i\n", inet_ntoa(Comm->srv.sin_addr), ntohs(Comm->srv.sin_port));
printf(">>%s", buf);
fflush(0);
}
}
}
}
服务器部分
//服务器main函数
#pragma once
#include <string.h>
#include<stdio.h>
#include<stdlib.h>
#include<winsock.h>
#define socklen_t int;
#pragma comment(lib,"wsock32.lib")
class CComm
{
private:
static void* ListenThread(void* data);
SOCKET ListenSocket; //等待接收数据的socket
sockaddr_in srv; //绑定地址
sockaddr_in client; //发送数据过来的地址
public:
CComm();
~CComm();
bool SendMsg(char* Msg, int Len);
bool Listen(int PortNum);
};
//CComm.h
#pragma once
#include <string.h>
#include<stdio.h>
#include<stdlib.h>
#include<winsock.h>
#define socklen_t int;
#pragma comment(lib,"wsock32.lib")
class CComm
{
private:
static void* ListenThread(void* data);
SOCKET ListenSocket; //等待接收数据的socket
sockaddr_in srv; //绑定地址
sockaddr_in client; //发送数据过来的地址
public:
CComm();
~CComm();
bool SendMsg(char* Msg, int Len);
bool Listen(int PortNum);
};
CComm.cpp
#include "CComm.h"
CComm::CComm()
{
//构造函数
ListenSocket = INVALID_SOCKET; // 开始设置为INVALID_SOCKET
#ifdef _WIN32 // 如果是win32系统
WORD VersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(VersionRequested, &wsaData); // 启动winsock服务
if (wsaData.wVersion != VersionRequested)
{
printf("Wrong version or WinSock not loaded\n");
fflush(0);
}
#endif
}
CComm::~CComm()
{//析构函数
if (ListenSocket != INVALID_SOCKET)
closesocket(ListenSocket); // 如果已经创建、则关闭
#ifdef _WIN32 // 调用WSACleanup
WSACleanup();
#endif
}
bool CComm::SendMsg(char* Msg, int Len)
{
signed int Sent;
//数据发送
Sent = send(ListenSocket, Msg, Len, 0);
if (Sent != Len)
{
printf("Error: failed to send udp message! \n");
fflush(0);
return false;
}
return true;
}
bool CComm::Listen(int PortNum)
{
ListenSocket = socket(PF_INET, SOCK_STREAM, 0);
if (ListenSocket == INVALID_SOCKET)
{
printf("Error: socket创建失败\n");
fflush(0);
return false;
}
srv.sin_family = PF_INET;
srv.sin_addr.s_addr = htonl(INADDR_ANY); // 任何地址
srv.sin_port = htons(PortNum);
if (bind(ListenSocket, (struct sockaddr*) & srv, sizeof(sockaddr)) != 0)
{
printf("绑定失败\n");
fflush(0);
closesocket(ListenSocket);
return false;
}
if (listen(ListenSocket, 10)!= 0) {
printf("%d", WSAGetLastError());
printf("侦听失败\n");
fflush(0);
closesocket(ListenSocket);
return false;
}
else {
printf("服务器已打开。\n正在等待客户端接入.......\n");
}
int len = sizeof(SOCKADDR);
ListenSocket = accept(ListenSocket, (struct sockaddr*) &client, &len);
if (ListenSocket == INVALID_SOCKET) {
printf("接受失败\n");
fflush(0);
closesocket(ListenSocket);
return false;
}
else {
char hostname[100], sendbuf[1024];
gethostname(hostname, 100);
sprintf_s(sendbuf, "欢迎 %s 连接到 %s!", inet_ntoa(client.sin_addr), hostname);
send(ListenSocket, sendbuf, strlen(sendbuf) + 1, 0);
}
int ThreadID; // 线程id
DWORD thread;
//调用createthread创建线程
ThreadID = (int)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(CComm::ListenThread), (void*)this, 0, &thread);
ThreadID = ThreadID ? 0 : 1; // 如果成功,则返回为0
if (ThreadID) // ThreadID如果不为0,则线程创建失败
{
printf("线程创建失败\n");
return false;
}
else
return true;
}
void* CComm::ListenThread(void* data)
{
char buf[4096];
CComm* Comm = (CComm*)data;
int len = sizeof(Comm->client);
bool flag = true;
while (1) // 一直循环
{
//接收数据
int result = recv(Comm->ListenSocket, buf, sizeof(buf) - 1, 0);
if (result > 0)
{
buf[result] = 0;
if (flag) {
printf("%s \n", buf);
flag = false;
}
else{
printf("Message received from host %s port %i\n", inet_ntoa(Comm->client.sin_addr), ntohs(Comm->client.sin_port));
printf(">>%s", buf);
fflush(0);
}
}
}
}
若想在VS上直接运行需要修改属性页配置属性调试中的命令参数,如在客户机中输入对方IP地址及对方用来侦听的端口号,而在服务器中输入用来侦听的端口号。
也可直接在cmd中直接运行debug中的exe文件,也要把相应的参数写在后面。如运行服务器代码先找到对应的exe文件所在的位置输入"服务器.exe 1000"。