server.cpp
上传用户:loctite114
上传日期:2007-01-03
资源大小:49k
文件大小:13k
源码类别:

棋牌游戏

开发平台:

Visual C++

  1. // Copyright (c) 1999 Lee Patterson
  2. // leepatterson@home.com
  3. //
  4. // Demonstrats: 
  5. //
  6. // o Internet Server that accepts telnet connections.
  7. // o Using multiple threads to handle more then one connection. 
  8. // o BlockingSocket class for using sockets. 
  9. //   (I'd recomend this class over the MS CSocket and such, as they still have 
  10. //     some 16-bit stuff in them, and this class ports to Unix a lot easier.
  11. //    That was the main goal of my program.)
  12. //
  13. // Also included:
  14. //
  15. // o Simple linked list class that can be used anywhere (unix/mfc/console).
  16. //    (Note: The linked list class is not thread safe.)
  17. //
  18. // I'd be happy to field any questions about the workings
  19. // of the server, or how I set things up, but I'm not interested in fixing 
  20. // up this server, or fixing any of the "chess game" bugs. Any bugs
  21. // found in the socket classes I would be interested in, although they are 
  22. // throughly tested.
  23. //
  24. // I built this server one night as a demo for a company in hopes
  25. // of getting a job there. Didn't know a damn thing about sockets
  26. // so I used, and built upon a blockingsocket class that was found 
  27. // in Inside Visual C++ 5.0 by MS PRESS.
  28. //
  29. // There are no rules to either game, so players can move whatever 
  30. // piece to whatever square. There isn't even any error checking,
  31. // and you can't backspace. This is a very limited server in that
  32. // respect.
  33. /* The layout of the server is:
  34. 1. Create an Accept thread to accept connections on port 23 (telnet)
  35. 2. Get a connection, create a new accept thread to be able to 
  36.    handle more connections.
  37. 3. Log this person in, getting user name.
  38. 4. Create a lobby of sorts where you can do simple chat, create a new
  39.    game, join a game, or watch a game.
  40. 5. This lobby reads a line of input from the socket, and then checks 
  41.    what the command the user typed was via ParsCmd. 
  42. 6. When the person creates a game, we add the game object to a pending 
  43.    list, and wait for someone to join the game.
  44. 7. When a person JOIN's a game, we check for the game name on the pending
  45.    list, and assign that person as the second player on that game object.
  46. 8. When you WATCH a game, you are added to a list of watches on that
  47.    game object.
  48.   The game objects:
  49. The base class is the BoardGame class. Chess and Checkers games are
  50. derived from BoardGame. This is to make a consistant interface
  51. for adding players to a board game, and drawing the board. 
  52. */
  53. //
  54. // NOTE:
  55. //
  56. //  There is probably a bit of an issue with people disconnecting,
  57. //  and things not being cleaned up. I never bothered to finish that 
  58. //  off, as it wasn't important. 
  59. // 
  60. #include <assert.h>
  61. #include <memory.h>
  62. #include <process.h>    /* _beginthread, _endthread */
  63. #include <iostream.h>
  64. #include <winsock.h>
  65. #include <stdlib.h>
  66. #include <stdio.h>
  67. #include <string.h> //strstr
  68. #include <llist.h>
  69. #include "blockingsocket.h"
  70. #include "gameob.h"
  71. int repeat=1;
  72. #define ASSERT assert
  73. #define VERIFY assert
  74. #define BUFFERSIZE 1000
  75. CLList m_games; //list of Chess Game Objects (NOTE: This isn't thread safe!)
  76. CLList m_pending; //list of games that are waiting for second player (NOTE: This isn't thread safe!)
  77. CLList m_connections; //list of all the people connected
  78. void log(const char* s)
  79. {
  80. printf("%sn",s);
  81. OutputDebugString(s);
  82. OutputDebugString("n");
  83. }
  84. //This is the main game loop. It reads in users moves, and prints out the board
  85. //contents to all people in a single game.
  86. void GameLoop(void* pParam)
  87. {
  88. log("GameLoop start");
  89. BoardGame* pgame=(BoardGame*)pParam;
  90. char* help= "Enter the column & row of the piece you are moving from & torn"
  91. "in the format FFTT. (ie: moving whites queen pawn ahead one from rn"
  92. "column 3, row 6 to column 3, row 5 would be entered 3635.)rn";
  93. char* entermove="What is your move? (?=help) ";
  94. char* whitesmove="It's whites move.";
  95. char* blacksmove="It's blacks move.";
  96. bool bAbort=false;
  97. bool bMadeMove=false;
  98. char inbuf[10];
  99. try
  100. {
  101. do
  102. {
  103. //handle whites move
  104. pgame->Draw();
  105. pgame->m_black->Print(whitesmove);
  106. bMadeMove=false;
  107. do
  108. {
  109. pgame->m_white->Write(entermove,strlen(entermove));
  110. pgame->m_white->ReadLine(inbuf,sizeof inbuf,300);
  111. if(!stricmp(inbuf,"quit"))
  112. {
  113. bAbort=true;
  114. pgame->m_white->Print("Aborting game");
  115. pgame->m_black->Print("White aborted game");
  116. }
  117. else if(!strcmp(inbuf,"?"))
  118. {
  119. pgame->m_white->Print(help);
  120. }
  121. else
  122. {
  123. if(strlen(inbuf)!=4)
  124. pgame->m_white->Print("Syntax error");
  125. else
  126. {
  127. if(pgame->ValidMove(inbuf[0],inbuf[1],inbuf[2],inbuf[3]))
  128. {
  129. bMadeMove=true;
  130. pgame->Move(inbuf[0],inbuf[1],inbuf[2],inbuf[3]);
  131. }
  132. else 
  133. pgame->m_white->Print("not a valid move");
  134. }
  135. }
  136. } while(!bMadeMove && !bAbort);
  137. //handle blacks move
  138. if(!bAbort)
  139. {
  140. pgame->Draw();
  141. pgame->m_white->Print(blacksmove);
  142. do
  143. {
  144. pgame->m_black->Write(entermove,strlen(entermove));
  145. pgame->m_black->ReadLine(inbuf,sizeof inbuf,300);
  146. if(!stricmp(inbuf,"quit"))
  147. {
  148. bAbort=true;
  149. pgame->m_black->Print("Aborting game");
  150. pgame->m_white->Print("Black aborted game");
  151. }
  152. else if(!strcmp(inbuf,"?"))
  153. {
  154.  pgame->m_black->Print(help);
  155. }
  156. else
  157. {
  158. if(strlen(inbuf)!=4)
  159. pgame->m_white->Print("Syntax error");
  160. else
  161. {
  162. bMadeMove=true;
  163. pgame->Move(inbuf[0],inbuf[1],inbuf[2],inbuf[3]);
  164. }
  165. }
  166. } while(!bMadeMove && !bAbort);
  167. }
  168. } while(!bAbort);
  169. }
  170. catch(const char* e)
  171. {
  172. log(e);
  173. }
  174. CLList* plist=m_games.FindItem(pgame);
  175. m_games.RemoveItem(plist);
  176. // delete pgame;
  177. log("GameLoop end");
  178. }
  179. //read in the persons user name, and make sure they are a valid user
  180. bool Login(CTelnetSocket* psocket)
  181. {
  182. char* login="Enter your login name (only "guest" works): ";
  183. char line[1000];
  184. psocket->Write(login,strlen(login));
  185. psocket->ReadLine(line,sizeof line);
  186. if(stricmp(line,"guest"))
  187. return false;
  188. psocket->m_wFlags |= CTelnetSocket::FLAG_VALIDATED;
  189. return true;
  190. }
  191. ChessGameOb* FindGame(const char* pgamename)
  192. {
  193. log("Findgame");
  194. ChessGameOb* o;
  195. CLList* plist=m_games.GetHead();
  196. while(plist)
  197. {
  198. o=(ChessGameOb*)plist->GetItem();
  199. log(o->m_gamename);
  200. if(!stricmp(o->m_gamename,pgamename))
  201. {
  202. //found the game name
  203. return o;
  204. }
  205. plist=plist->GetNext();
  206. }
  207. return NULL;
  208. }
  209. ChessGameOb* FindPendingGame(const char* pgamename)
  210. {
  211. log("Find pending game");
  212. ChessGameOb* o;
  213. CLList* plist=m_pending.GetHead();
  214. while(plist)
  215. {
  216. o=(ChessGameOb*)plist->GetItem();
  217. log(o->m_gamename);
  218. if(!stricmp(o->m_gamename,pgamename))
  219. {
  220. //found the game name
  221. return o;
  222. }
  223. plist=plist->GetNext();
  224. }
  225. return NULL;
  226. }
  227. enum
  228. {
  229. CREATE=1,
  230. JOIN,
  231. WATCH,
  232. QUIT,
  233. PLAY,
  234. COLOR
  235. };
  236. char* cmds[]={"create","join","watch","quit","play","color"};
  237. int FindToken(const char* buf)
  238. {
  239. for(int i=0; i<sizeof cmds/sizeof cmds[0]; i++)
  240. {
  241. if(strstr(buf,cmds[i]))
  242. return i+1;
  243. }
  244. return 0;
  245. }
  246. //send the chat in buf to all connections
  247. void Chat(CPersonInstance* pInstance, char* buf)
  248. {
  249. CPersonInstance* o;
  250. CLList* plist=m_connections.GetHead();
  251. while(plist)
  252. {
  253. o=(CPersonInstance*)plist->GetItem();
  254. if(o!=pInstance)
  255. o->Print(buf);
  256. plist=plist->GetNext();
  257. }
  258. }
  259. //Look at what the user typed, and act upon it.
  260. bool ParsCmd(char* buf,CPersonInstance* pInstance)
  261. {
  262. char* SyntaxErrorMsg="Syntax error. 'create chess|checkers name' " ;
  263. int itoken=FindToken(buf);
  264. char cmd[30],parm1[30],parm2[30];
  265. BoardGame* pgame;
  266. CLList* plist;
  267. switch(itoken)
  268. {
  269. case WATCH:
  270. //user typed "watch game"
  271. sscanf(buf,"%s %s",cmd,parm1);
  272. pgame=FindGame(parm1);
  273. if(!pgame)
  274. pInstance->Print("No game found");
  275. else
  276. {
  277. if(!pgame->HasAllPlayers())
  278. pInstance->Print("Both players have to be playing befor watchin is aloud");
  279. else
  280. {
  281. pgame->AddWatcher(pInstance);
  282. pInstance->Print("You will see the board when the next person moves");
  283. }
  284. return true;
  285. }
  286. break;
  287. case CREATE:
  288. //user typed "create chess game"
  289. if(3!=sscanf(buf,"%s %s %s",cmd,parm1,parm2)) //get game name
  290. {
  291. pInstance->Print(SyntaxErrorMsg);
  292. }
  293. else
  294. {
  295. if(!stricmp(parm1,"checkers"))
  296. {
  297. pgame=new CheckerGameOb(pInstance,parm2);
  298. pInstance->Print("Created new checkers game");
  299. }
  300. else if(!stricmp(parm1,"chess"))
  301. {
  302. pInstance->Print("Created new chess game");
  303. pgame=new ChessGameOb(pInstance,parm2);
  304. }
  305. else
  306. {
  307. pInstance->Print(SyntaxErrorMsg);
  308. return false;
  309. }
  310. m_pending.AddTail(pgame);
  311. #if 1
  312. log("Pending games:");
  313. plist=m_pending.GetHead();
  314. while(plist)
  315. {
  316. pgame=(BoardGame*)plist->GetItem();
  317. log(pgame->m_gamename);
  318. plist=plist->GetNext();
  319. }
  320. #endif
  321. pInstance->Print("You must now wait till someone joins your game");
  322. return true;
  323. }
  324. break;
  325. case JOIN:
  326. //user typed "join game"
  327. sscanf(buf,"%s %s",cmd,parm1);
  328. pgame=FindPendingGame(parm1);
  329. if(pgame)
  330. {
  331. pgame->AddBlack(pInstance);
  332. plist=m_pending.FindItem(pgame);
  333. if(plist)
  334. m_pending.RemoveItem(plist);
  335. m_games.AddTail(pgame);
  336. _beginthread(GameLoop,0,pgame);
  337. return true;
  338. }
  339. else
  340. {
  341. pInstance->Print("No game found");
  342. }
  343. break;
  344. case QUIT:
  345. //user typed "quit"
  346. pInstance->Print("Good bye");
  347. pInstance->Close();
  348. delete pInstance;
  349. return true;
  350. default:
  351. //LBP (01/08/99): Print this chat to all players in the lobby.
  352. Chat(pInstance,buf);
  353. break;
  354. }
  355. return false;
  356. }
  357. //LBP (01/08/99): this is the lobby of sorts.
  358. void TalkProc(void* pParam)
  359. {
  360. log("TalkProc start");
  361. char* msg[]=
  362. {
  363. "Type 'create name' to make a game where 'name' is the game name you choose.rn"  //0
  364. "Type 'join name' to join a player that created a game.rn"
  365. "Type 'watch name' to watch a game in progress",
  366. "Good bye.", //1
  367. "Syntax Error" //2
  368. };
  369. CPersonInstance* pInstance=(CPersonInstance*)pParam;
  370. char inbuf[CTelnetSocket::nSizeRecv];
  371. bool bAbort=false;
  372. m_connections.AddTail(pInstance);
  373. try
  374. {
  375. pInstance->Print(msg[0]);
  376. do
  377. {
  378. pInstance->Write("% ",2);
  379. pInstance->ReadLine(inbuf,sizeof inbuf,1800);
  380. if(ParsCmd(inbuf,pInstance))
  381. {
  382. bAbort=true;
  383. }
  384. } while(!bAbort);
  385. }
  386. catch(const char* e)
  387. {
  388. log(e);
  389. pInstance->Cleanup();
  390. delete pInstance;
  391. }
  392. log("TalkProc end");
  393. _endthread();
  394. }
  395. void AcceptProc(void* pParam)
  396. {
  397. CBlockingSocket* psockListen=(CBlockingSocket*)pParam;
  398. CSockAddr saClient;
  399. CPersonInstance sConnect;
  400. char* buffer;
  401. try 
  402. {
  403. char* welcome="Welcome to the club.";
  404. char* nonuser="Sorry, members only";
  405. buffer=(char*)calloc(1,1000);
  406. assert(buffer);
  407. if(!psockListen->Accept(sConnect,saClient))
  408. _endthread();
  409. _beginthread(AcceptProc,0,pParam); //get ready for another connection
  410. log("Connection accepted");
  411. if(!Login(&sConnect))
  412. {
  413. sConnect.Print(nonuser);
  414. sConnect.Close();
  415. }
  416. else
  417. {
  418. sConnect.Print(welcome);
  419. //LBP (01/08/99): start up a lobby for this new connection
  420. CPersonInstance* newinstance=new CPersonInstance(sConnect);
  421. _beginthread(TalkProc,0,newinstance);
  422. }
  423. }
  424. catch(const char* e)
  425. {
  426. log(e);
  427. sConnect.Cleanup();
  428. }
  429. _endthread();
  430. }
  431. void CheckKey(void* dummy)
  432. {
  433. int a;
  434. cin >> a;
  435. repeat=0;
  436. }
  437. void ProcessGames()
  438. {
  439. _beginthread(CheckKey,0,NULL);
  440. do
  441. {
  442. } while(repeat);
  443. }
  444. void main(void)
  445. {
  446. CBlockingSocket sockListen;
  447. WSADATA wsd;
  448. if(WSAStartup(0x0101,&wsd)!=0)
  449. {
  450. cout << "Unable to start socketn";
  451. }
  452. else
  453. {
  454. cout << "Chess Server Demo by Lee Pattersonn";
  455. cout << "leepatterson@home.comnn";
  456. cout << "Demonstrates an object oriented server that can handlen";
  457. cout << "any number of chess games with 2 players and any number ofn";
  458. cout << "watchers per game.nn";
  459. cout << "Use telnet as a client connect to this server (ie: telnet localhost).n";
  460. cout << "Server uses port 23 (telnet default).n";
  461. cout << "Ctrl+c exits server";
  462. try 
  463. {
  464. CSockAddr saServer(INADDR_ANY,23);
  465. sockListen.Create();
  466. sockListen.Bind(saServer);
  467. sockListen.Listen();
  468. _beginthread(AcceptProc,0,&sockListen);
  469. }
  470. catch(const char* e)
  471. {
  472. sockListen.Cleanup();
  473. cout << e << "n";
  474. }
  475. ProcessGames();
  476. try
  477. {
  478. sockListen.Close();
  479. Sleep(300);
  480. WSACleanup();
  481. }
  482. catch(const char* e)
  483. {
  484. cout << e << "n";
  485. }
  486. }
  487. }