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++的黑科技系列,以后会持续更新,大家可以收藏作为资料使用!