实现两(多)台windows电脑使用TCP套接字通信(亲测简单有效)

实现两(多)台windows电脑使用TCP套接字通信(亲测简单有效)

目录

一、前言

二、详细步骤

1.两台电脑连网(同一WIFF)

2.断开网络防火墙

3.获取网络IP地址

4.修改客户端绑定的IP地址

5.连接测试

三、源码

1.服务端代码:

2.客户端代码:

一、前言

我们在学习完windows网络编程后,我想大多数人心底一直都有一个问题。

网络编程就是实现多台电脑进行通信的,可我们自己在学习测试的时候,服务器端和客户端都是自己的电脑进行通信(此时ip地址为本机127.0.0),而这样的学习效果没有那么显著,没有发挥真正的网络通信的功能。

那下面就跟着我的步骤:只需要准备两台电脑,服务端和客户端源代码即可实现。

二、详细步骤

1.两台电脑连网(同一WIFF)

我们的第一步骤就是保证两台电脑连上同一个WIFF,手机热点也可以(座机情况不考虑,需要额外步骤)。

2.断开网络防火墙

这一步很重要,我们需要断开自己电脑的防火墙(保护机制),要不然不能实现电脑通信。

3.获取网络IP地址

(注意:这一步骤需要获取的是服务端的IP地址。)第一步: WIN + R , 输入cmd,回车。

第二步:输入 ipconfig,获取连接无线网 WIFF 的 IPv4 地址。

4.修改客户端绑定的IP地址

在上一个步骤获取网络ip地址后,我的是 192.168.0.101,修改客户端代码绑定的IP地址。

5.连接测试

我们需要将准备的两台电脑一台电脑作为服务端,另一台(客户端可以有多个,多台电脑也可以)作为客户端,分别启动项目,连接测试。

这里我用的是我写的的项目代码,可以参考多线程网络实战之仿qq群聊的服务器和客户端,

我这里测试的仿照qq的通过服务器,多个客户端通过通信。测试结果如下:

服务端:

客户端:

三、源码

这里你可以用自己的代码最好,我的代码有些复杂,不推荐,而且运行需要用开发者平台打开,参考文章:多线程网络实战之仿qq群聊的服务器和客户端

1.服务端代码:

如下所示:

// 1. 对于每一个上线的客户端,服务端会起一个线程去维护

// 2. 将受到的消息转发给全部的客户端

// 3. 当某个客户端断开(下线),需要处理断开的链接。怎么处理呢?

#include

#include

#include

#include

#pragma comment(lib, "ws2_32.lib")

#define MAX_CLEN 256

#define MAX_BUF_SIZE 1024

SOCKET clnSockets[MAX_CLEN]; // 所有的连接客户端的socket

int clnCnt = 0; // 客户端连接的个数

HANDLE hMutex;

// 将收到的消息转发给所有客户端

void SendMsg(char* msg, int len)

{

int i;

WaitForSingleObject(hMutex, INFINITE);

for (i = 0; i < clnCnt; i++)

{

send(clnSockets[i], msg, len, 0);

}

ReleaseMutex(hMutex);

}

// 处理消息, 收发消息

unsigned WINAPI handleCln(void *arg)

{

SOCKET hClnSock = *((SOCKET *)arg);

int iLen = 0;

char recvBuff[MAX_BUF_SIZE] = { 0 };

while (1)

{

// iLen 成功时返回接收的字节数(收到EOF时为0),失败时返回SOCKETERROR。

iLen = recv(hClnSock, recvBuff, MAX_BUF_SIZE, 0);

//

if (iLen >= 0)

{

// 将收到的消息转发给所有客户端

SendMsg(recvBuff,iLen);

}

else

{

break;

}

}

printf("此时连接的客户端数量 = %d\n", clnCnt);

WaitForSingleObject(hMutex, INFINITE);

for (int i = 0; i < clnCnt; i++)

{

// 找到哪个连接下线的,移除这个连接

if (hClnSock == clnSockets[i])

{

while (i++ < clnCnt)

{

clnSockets[i] = clnSockets[i + 1];

}

break;

}

}

// 断开连接减 1

clnCnt--;

printf("断开连接后连接的客户端数量 = %d\n", clnCnt);

ReleaseMutex(hMutex);

// 断开连接

closesocket(hClnSock);

return 0;

}

int main(int argc, char* argv[])

{

printf("this is Server\n");

//0. 初始化网络

#if 1

// 0 初始化网络库

// 初始化库

WSADATA wsaData;

int stu = WSAStartup(MAKEWORD(2, 2), &wsaData);

if (stu != 0) {

std::cout << "WSAStartup 错误:" << stu << std::endl;

return 0;

}

#endif

HANDLE hThread;

// 1. 创建一个互斥对象

hMutex = CreateMutex(NULL, false, NULL);

// 2. socket 创建套接字

SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);

if (sockSrv == INVALID_SOCKET)

{

std::cout << "socket failed!" << GetLastError() << std::endl;

WSACleanup(); //释放Winsock库资源

return 1;

}

// 3 bind 绑定套接字

SOCKADDR_IN addrSrv;

addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 地址 IP地址any

addrSrv.sin_family = AF_INET; // ipv4协议

addrSrv.sin_port = htons(6000); // 端口号

if ( SOCKET_ERROR == bind(sockSrv, (sockaddr*)&addrSrv, sizeof(SOCKADDR)))

{

std::cout << "bind failed!" << GetLastError() << std::endl;

WSACleanup(); //释放Winsock库资源

return 1;

}

// 4. 监听

if (listen(sockSrv, 5) == SOCKET_ERROR) // 5 是指最大的监听数目,执行到listen

{

printf("listen error = %d\n", GetLastError());

return -1;

}

// 5

SOCKADDR_IN addrCli;

int len = sizeof(SOCKADDR);

while (true)

{

// 接受客户端的连接

SOCKET sockCon = accept(sockSrv, (sockaddr*)&addrCli, &len);

// 全局变量要加锁

WaitForSingleObject(hMutex, INFINITE);

// 将连接放到数组里面

clnSockets[clnCnt++] = sockCon;

// 解锁

ReleaseMutex(hMutex);

// 每接收一个客户端的连接,都安排一个线程去维护

hThread = (HANDLE)_beginthreadex(NULL, 0, &handleCln, (void*)&sockCon, 0, NULL);

printf("Connect client IP = %s\n, Num = %d \n", inet_ntoa(addrCli.sin_addr), clnCnt);

}

closesocket(sockSrv);

CloseHandle(hMutex);

WSACleanup();

return 0;

}

2.客户端代码:

如下所示:

// 客户端做的事情:

//1 请求连接上线,

//2 发消息

//3 客户端等待服务端的消息

//4 等待用户自己的关闭(下线)

#include

#include

#include

#include

#pragma comment(lib, "ws2_32.lib")

#define NAME_SIZE 256

#define MAX_BUF_SIZE 1024

char szName[NAME_SIZE] = "[DEFAULT]"; // 默认的昵称

char szMsg[MAX_BUF_SIZE]; // 收发数据的大小

unsigned WINAPI SendMsg(void* arg)

{

SOCKET hClnSock = *((SOCKET*)arg);

char szNameMsg[NAME_SIZE + MAX_BUF_SIZE] = { 0 }; // 昵称和消息

while (1)

{

memset(szMsg, 0, MAX_BUF_SIZE);

// 阻塞这一句,等待控制台的消息

//fgets(szMsg, MAX_BUF_SIZE, stdin);

std::cin >> szMsg;

if (!strcmp(szMsg, "Q\n") || !strcmp(szMsg, "q\n"))

{

// 处理下线

closesocket(hClnSock);

exit(0);

}

// 拼接 名字和字符串一起发送

sprintf_s(szNameMsg, "%s %s", szName, szMsg);

send(hClnSock, szNameMsg, strlen(szNameMsg) + 1, 0);

}

}

unsigned WINAPI RecvMsg(void* arg)

{

SOCKET hClnSock = *((SOCKET*)arg);

char szNameMsg[NAME_SIZE + MAX_BUF_SIZE] = { 0 }; // 昵称和消息

int len;

while (1)

{

len = recv(hClnSock, szNameMsg, sizeof(szNameMsg), 0);

if (len <= 0)

{

break;

return -2;

}

szNameMsg[len] = 0;

std::cout << szNameMsg << std::endl;

// fputs(szNameMsg, stdout);

}

}

int main(int argc, char* argv[])

{

if (argc != 2)

{

printf("必须输入两个参数,包括昵称\n");

printf("例如: WXS\n");

system("pause");

return -1;

}

sprintf_s(szName, "[%s]", argv[1]);

printf("this is Client");

//0. 初始化网络

#if 1

// 0 初始化网络库

// 初始化库

WSADATA wsaData;

int stu = WSAStartup(MAKEWORD(2, 2), &wsaData);

if (stu != 0) {

std::cout << "WSAStartup 错误:" << stu << std::endl;

return 0;

}

#endif

// 定义两个线程

HANDLE hSendThread, hRecvThread;

// 1. 建立 socket

SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);

if (sockCli == INVALID_SOCKET)

{

std::cout << "socket failed!" << GetLastError() << std::endl;

WSACleanup(); //释放Winsock库资源

return 1;

}

// 2, 配置IP地址 和 端口号

SOCKADDR_IN addrSrv;

addrSrv.sin_family = AF_INET; // ipv4协议

addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.7"); // 地址 IP地址any

addrSrv.sin_port = htons(6000); // 端口号

// 3. 连接服务器

int res = connect(sockCli, (sockaddr*)&addrSrv, sizeof(sockaddr));

// 4. 发送服务器消息,启动线程

hSendThread = (HANDLE)_beginthreadex(NULL, 0, &SendMsg, (void*)&sockCli, 0, NULL);

// 5. 等待

hRecvThread = (HANDLE)_beginthreadex(NULL, 0, &RecvMsg, (void*)&sockCli, 0, NULL);

WaitForSingleObject(hSendThread,INFINITE);

WaitForSingleObject(hRecvThread, INFINITE);

closesocket(sockCli);

WSACleanup();

return 0;

}

相关推荐

真三国无双5中唤马的方法是什么?
bst365.com

真三国无双5中唤马的方法是什么?

📅 07-27 👁️ 3920
Excel表格怎么换行?3种方法6种换行符分享
bst365.com

Excel表格怎么换行?3种方法6种换行符分享

📅 07-19 👁️ 9606
机票退票怎么扣费 机票退票多久能到账户
365bet线上注册

机票退票怎么扣费 机票退票多久能到账户

📅 07-02 👁️ 7262
使用 PIN 码保护 SIM 卡
bst365.com

使用 PIN 码保护 SIM 卡

📅 07-26 👁️ 4023