科技系列 - 2 < 更新第二期 >:DEV - C++ 不同主机下的同局域网联机 更新 第 2 期


DEV - C++ 不同主机下的联机 更新 第 Ⅱ 期

首期文章链接


上上期补充说明

相信很多人都发现上一期的程序无法 编译运行 (原因未知) ,我们只需要给程序的 编译命令( DEV-C++ 编译器 → 工具 → 编译选项 → 编译命令) 加上 -lws2_32 且把 #pragma 语句去掉就行了!!!


本期更新说明

本期更新将原有风格全部改变

新加:

1、可支持多人联机模式(运用多线程知识)

2、改换成由 客户端 -> 服务端 -> 客户端 的方法多人通话

3、可以设置服务器密码

注意:所有警告均为英语!

以下全文纯手打,给个 赞 行吗


版本 - 3

服务端
#include<bits/stdc++.h> 

#include<Winsock2.h>

#include<windows.h>

#include<queue>

#pragma comment (lib,"ws2_32") 

//使用 Winsock2.h 时需要用 ws2_32.lib 文件 

//如果出现编译错误 xxx.cpp:(.text+xxx): undefined reference to `__imp_xxx'

//可在编译命令处 添加 -lws2_32 

#define size 6400 // 缓冲区长度 

#define port 9999 // 端口号 

#define people 5 //限制人数 

using namespace std;

queue<char*> print; //发送信息缓冲

char names[10000][105]; //存储昵称 

SOCKET server; //接受 SOCKET 用 

SOCKET lient[100000]; //最多可承载次数 

int times_lient[100000]; //存储承载下标 ( 用来删除下线状态 ) 

int times; //承载过的次数 

int online; //在线人数 

char keys[1000];

bool p1_tf; //延时判断

bool p2_tf = true;

void get_keys()
{
	puts("Please set the room password! ( keys len < 50 )\n");
	
	gets(keys);
	
	puts("");
	
	if(strlen(keys) >= 50)
	
		printf("Oops! len = %d ( >= 50 )\n\n",strlen(keys)),
	
		get_keys();
}

DWORD WINAPI recvs(LPVOID param)
{
	SOCKET sclient = lient[times];
	
	p1_tf = false;
	
	int reg;
	
	char recvn[10000];
	
	memset( recvn , 0 , sizeof(recvn) );
	
	while(1)
	{
		memset( recvn , 0 , sizeof(recvn) );
		
		reg = recv(sclient , recvn , size , 0);
		
		if(reg == -1)
		
			break;
		
		else
		{
			printf("From %s : %s\n\n",names[sclient],recvn);
			
			char sssn[1000];
			
			memset(sssn,0,sizeof(sssn));
            
        	memcpy(sssn,names[sclient],strlen(names[sclient]));
        	
        	sssn[strlen(sssn)] = ':';
        	
            strcat(sssn,recvn);
            
            strcat(sssn,"\n");
            
            print.push(sssn);
		}
	}
	
	strcat(names[sclient]," left!\n");
    
    printf("%s\n\n",names[sclient]);
    
    lient[ times_lient[sclient] ] = -1;
    
    print.push(names[sclient]);
    
    online -- ;

    closesocket(sclient);
}

DWORD WINAPI sends(LPVOID param)
{
    while(1)

    	if(!print.empty() and p2_tf)
    	{
    		int ans = 0;
    		
    		for(int i = 1;i <= times;i ++)
    		
    			if(lient[i] != -1) 

    				send( lient[i] , print.front() , strlen(print.front()) , 0 ) ,
					
					ans++;
    				
    			else if(ans == online)
    			
    				break;

			print.pop(); 
		}

}

void find_socket()
{
	get_keys();
	
	sockaddr_in client;
	
    int client_len = sizeof( client );
	
	CreateThread(NULL, 0, sends , NULL, 0 , NULL);
	
	puts("Socket is open!\n");
	
	while(1)
	{
		if(times > 99999)
		{
			puts("Error 5 - Upper limit reached!\n ");
			
			puts("The server cannot be turned on normally!\n");
		
			puts("Close in five seconds!\n");
		
			Sleep(5000);
		
			exit(0);
		}
		
		if(online >= people)
		{
			printf("Error 6 - The number of people online has reached the maximum! ( %d People ) : ( Now %d people) \n\n ",people,online);
		
			puts("Please wait!\n");
		
			while(online >= people);
		}
		
		while(p1_tf);
		
		lient[++times] = accept( server, ( sockaddr FAR* )&client, &client_len );
		
		p2_tf = false;
		
		if( lient[times] == (SOCKET)(~0) )
		{
			puts("Error 7 - Access failure!\n ");
			
			times--;
			
			continue;
		}
		
		times_lient[lient[times]] = times;
		
		char phj[1000];
		
		memset(phj,0,sizeof(phj));
		
		int ret = recv( lient[times] , phj , size , 0);
		
		char keyss[1000];
		
		memset(keyss,0,sizeof(keyss));
		
		int yi = 0 , pi = 0;
		
		while(phj[pi] != ',')
		{
			names[lient[times]][pi] = phj[pi];
			
			pi++;
		}
		
		pi++;
		
		while(phj[pi] != ',')
		{
			keyss[yi ++] = phj[pi];
			 
			pi++;
		}

		if( strcmp( keys , keyss ) != 0 )
		{
			int reg = send( lient[times] , "-1" , strlen( "-1") , 0);
			
			printf("From [%s] , name [%s] password error!\n\n",reg,inet_ntoa(client.sin_addr),names[lient[times]]);
			
			Sleep(1000);
			
			times -- ;
			
			continue;
		}
		
		online ++;
		
		send( lient[times] , "-n-" , strlen( "--") , 0);
		
		printf("From [%s] , name :[%s] join successfully!\n\n",inet_ntoa(client.sin_addr),names[lient[times]]);
		
		char sssn[1000];
		
		memset(sssn,0,sizeof(sssn));
		 
    	memcpy(sssn,names[lient[times]],strlen(names[lient[times]]));
    	
    	strcat(sssn," 加入了服务器\n");
//    	
		print.push(sssn);
		
		p1_tf = p2_tf = 1;
		
		CreateThread(NULL, 0, recvs , NULL, 0 , NULL);
	}
}

void open_socket()
{
	/*
	This is an important part of communication.
	*/
	
	WSADATA wsaData;
	
	if( WSAStartup( MAKEWORD( 2 , 2 ) , &wsaData ) != 0)
	{
		puts("Error 1 - Winsock Load Error!\n");
		
		puts("The server cannot be turned on normally!\n");
		
		puts("Close in five seconds!\n");
		
		Sleep(5000);
		
		exit(0);
	}
	
	server = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP );
	            
	if( server == (SOCKET)(~0) )
	{
		puts("Error 2 - Socket Error!\n");
		
		puts("The server cannot be turned on normally!\n");
		
		puts("Close in five seconds!\n");
		
		Sleep(5000);
		
		WSACleanup();
		
		exit(0);
	}
	
	sockaddr_in bindser;
	
	bindser.sin_family = AF_INET; 
	
	bindser.sin_port = htons( port ); //指向端口号 
	
	bindser.sin_addr.s_addr = htonl( INADDR_ANY ); //指向全部人可连接
	
	if( bind( server , ( const struct sockaddr* ) &bindser , sizeof( bindser ) ) == (SOCKET)(~0) )
	{
		puts("Error 3 - Bind Error!\n");
		
		puts("The server cannot be turned on normally!\n");
		
		puts("Close in five seconds!\n");
		
		Sleep(5000);
		
        WSACleanup();
        
        closesocket( server );
		
		exit(0);
	}
	
	if( listen( server , people ) == (SOCKET)(~0) )
	{
		puts("Error 4 - Listen Error!\n");
		
		puts("The server cannot be turned on normally!\n");
		
		puts("Close in five seconds!\n");
		
		Sleep(5000);
		
        WSACleanup();
        
        closesocket( server );
		
		exit(0);
	}
}

int main()
{
	puts("Welcome to English LAN communicator!\n");
	
	open_socket(); // 开启 
	
	find_socket(); // 寻找 
} 
客户端
#include<bits/stdc++.h> 

#include<Winsock2.h>

#include<windows.h>

#include<queue>

#pragma comment (lib,"ws2_32") 

#define port 9999 

#define size 6400 // 缓冲区长度 

//使用 Winsock2.h 时需要用 ws2_32.lib 文件 

//如果出现编译错误 xxx.cpp:(.text+xxx): undefined reference to `__imp_xxx'

//可在编译命令处 添加 -lws2_32 

SOCKET server;

char your_name[1000];

char ipv4[1000];

char keys[1000];

void recvs()
{
	int rag;
	
	char recvn[100000];
	
	memset(recvn,0,sizeof(recvn));
	
	while(1)
	{
		memset( recvn , 0 , sizeof(recvn) );
		
		rag = recv(server,recvn,size,0);
		
		if(rag == -1)
		{
			puts("Error 5 - Disconnect the server!\n");
			
			break;
		}
		
		printf("%s\n",recvn);
	}
}

DWORD WINAPI sends(LPVOID param)
{
	char sendn[100000];
	
	memset( sendn , 0 , sizeof(sendn) );
	
	while(1)
	{
		puts("Send len < 1000\n");
		
		memset( sendn , 0 , sizeof(sendn) );
		
		gets(sendn);
		
		puts("");
		
		if(strlen(sendn) >= 1000)
		{
			printf("Oops! len = %d ( >= 1000 )\n\n",strlen(keys));
			
			continue;
		}
		
		int rag = send(server,sendn,strlen(sendn),0);
		
		if(rag == -1) break;
	}
}

void open_socket()
{
	WSADATA wsaData;
	
	if( WSAStartup( MAKEWORD( 2 , 2 ) , &wsaData ) != 0) 
	{
		puts("Error 1 - Winsock Load Error!\n");
		
		puts("The server cannot be turned on normally!\n");
		
		puts("Close in five seconds!\n");
		
		Sleep(5000);
		
		exit(0);
	}
	
	server = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP );
	            
	if( server == (SOCKET)(~0) )
	{
		puts("Error 2 - Socket Error!\n");
		
		puts("The server cannot be turned on normally!\n");
		
		puts("Close in five seconds!\n");
		
		Sleep(5000);
		
		WSACleanup();
		
		exit(0);
	}

	set_name:

	puts("Please set your name! ( name len < 20 )\n");
	
	gets(your_name);
	
	puts("");
	
	if(strlen(your_name) >= 20)
	{ 
	
		printf("Oops! len = %d ( >= 20 )\n\n",strlen(your_name)); 
		
		goto set_name;
		
	} 
	
	set_ipv4:

	puts("Please set ipv4\n");
	
	gets(ipv4);
	
	puts("");
	
	sockaddr_in conser;
	
	conser.sin_family = AF_INET; 
	
	conser.sin_port = htons( port ); //指向端口号 
	
	conser.sin_addr.S_un.S_addr = inet_addr(ipv4);
	
	set_keys:

	puts("Please set key\n");
	
	gets(keys);
	
	puts("");
	
	for(int i = 1;i <= 10;i++)
	{
		if(connect( server, (LPSOCKADDR)&conser, sizeof( conser ) ) == (SOCKET)(~0) )
		{
			if(i == 10)
			{
				puts("Error 3 - IP Error!\n");
		
				goto set_ipv4;
		
				exit(0);
			}
		}
		else
		{
			break;
		}
	}
	
	strcat(your_name,",");
	
	strcat(your_name,keys);
	
	strcat(your_name,",");
	
	send(server,your_name,strlen(your_name),0);
	
	char yes[100];
	
	memset(yes,0,sizeof(yes));
	
	int reg = recv(server,yes,size,0);
	
	if(strcmp(yes,"-n-") == 0)
	{
		puts("Error 4 - Key Errer!\n");
		
		Sleep(5000);
		
		return;
		
	}
	
	HANDLE hThread1 = CreateThread(NULL, 0, sends, NULL, 0, NULL);

	recvs();
	
    ::CloseHandle(hThread1);
         
    closesocket( server );
    
    WSACleanup(); // 资源释放

}

int main()
{
	again:
	
	open_socket();
	
	goto again;
}

使用说明

同局域网下方可链接


以后我会持续更新关于 DEV-C++ 联机的程序,以帮助大家利用联网制作更多有用的东西 “勿整蛊!!”

关于DEV-C++的黑科技系列,以后会持续更新,大家可以收藏作为资料使用!


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值