Тема 9. Создание серверных приложений

Задача - создать кроссплатформенный клиент-сервер протокол.

Функционал серверной части реализованы на C++, чтобы приложение легко компилировалось под debian mini через g++.

 

Нам понадобится:

 

  1. #include <iostream>

  2. #include <sstream>

  3. #include <map>

  4. #include <fstream>

  5. #include <algorithm>

  6. #include <time.h>

  7. #include <cstring>

  8. #include <stdlib.h>

  9. #include <iostream>

10. #include <sys/types.h>

11. #include <string.h>

12. #include <assert.h>

13. #include <stdio.h>

14. #include <sstream>

15. #include <math.h>

16. #include <sys/socket.h>

17. #include <netinet/in.h>

18. #include <arpa/inet.h>

19. #include <unistd.h>

20. #include <pthread.h>

 

* This source code was highlighted with Source Code Highlighter.

 

Функция запуска нашего сервера:

 

  1. pthread_t mainThreadID; //id главного потока сервера

  2. int mainThread; //результат запуска потока

  3. int server_port; //порт, по которому мы работаем

  4. 

  5. void startServer(string s, int port)

  6. {

  7. server_port = port;

  8. 

  9. //string s - можем послать какую-то информацию, например arg

10. mainThread = pthread_create(&mainThreadID, NULL, &serverProcess, (void *)&s); //запускаем поток

11. }

 

* This source code was highlighted with Source Code Highlighter.

 

Наш основной поток сервера:

 

  1. void* serverProcess(void* arg)

  2. {

  3. int server_sockfd;

  4. 

  5. int err=-1;

  6. int server_len;

     7. struct sockaddr_in server_address;

  8.  

  9. int client_sockfd;

10. socklen_t client_len;

11. struct sockaddr_in client_address;

12. server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

13.    

14.   server_address.sin_family = AF_INET;

15. server_address.sin_addr.s_addr = htonl(INADDR_ANY);

16. server_address.sin_port = htons(server_port); //наш порт

17. server_len = sizeof(server_address);

18. 

19. err = bind(server_sockfd, (struct sockaddr *) &server_address, server_len);

20. if(err!= 0) //не получилось "забить" порт

21. {

22. printf("[bind error!]\n");

23. exit(-1);

24. }

25. err = -1;

26.    

27. err = listen(server_sockfd, 5);

28. if(err!= 0) //не получилось начать прослушивание

29. {

30. printf("[listen error!]\n");

31. exit(-1);

32. }

33. 

34. while(1)

35. {

36.  client_len = sizeof(client_address);

37.  client_sockfd = accept(server_sockfd, (struct sockaddr *) &client_address, &client_len);

38.  if(client_sockfd > 0){ //ага! новый клиент подключился

39.    at++;

40. 

41.    client cl;

42.    cl.sockfd = client_sockfd;

43.    cl.len = client_len;

44.    cl.addr = client_address;

45.        cl.alive = true;

46.    cl.threadIndex = at;

47.    cl.data.loginned = false;

48.    cl.data.connectTime = time(0);

49.    cl.data.p_login = "";

50.    cl.data.p_password = "";

51.    ac++;

52.    allclients[ac] = cl;

53. 

54.    allthreads[at].threadInd = pthread_create(&allthreads[at].threadID, NULL, &socketRead, (void *)&ac); //запускаем поток для клиента

55.  }

56. }

57. }

 

* This source code was highlighted with Source Code Highlighter.

 

 

Код «прослушивания» клиента:

 

  1. void* socketRead(void* arg)

  2. {

  3. int clID = *((int*)arg);

  4. client cl = allclients[clID];

  5. int client_sockfd = cl.sockfd;

  6. 

  7. onConnect(clID, cl); //вызываем onConnect

  8. 

  9. string bf = "";

10. 

11. while(1)

12. {

13.  char buf[1000000];

14. int len;

15. 

16. string sr = "";

17. string pcg = "";

18. 

19. len = read(client_sockfd, buf, sizeof(buf));

20. 

21. if(len > 0) //что-то пришло от клиента

  22. {

23.  pcg = buf;

24.  pcg = pcg.substr(0, len);

25.  bf.append(pcg); //склейка пакета

26. 

27.  int ps = -1;

28. 

29.  ps = bf.find("\r\n"); //пакет заканчивается на "\r\n" - скорее всего Windows:)

30.  if(ps == -1) ps = bf.find("\n"); //пакет заканчивается на "\n" - скорее всего Linux:)

31.  if(ps!= -1) //конец пакета имеется

32.  {

33.    onWrite(clID, cl, bf); //вызываем onWrite

34.    bf = "";

35.  }

36. }else

37. {

38.  if(len == 0) //если len = 0, значит, что клиент отключился

39.  {

40.    onDisconnect(clID, cl); //вызываем onDisconnect

41.    

42.    cl.alive = false;

43.    cl.data.disconnectTime = time(0);

44.    allclients[clID] = cl;

45.    // pthread_detach(); // можно вызвать

46.    //shutdown(client_sockfd, 0); //и это на всякий случай:)

47.    //close(client_sockfd);

48.    pthread_exit((void*)NULL);

49.  }

50. }

51. }

52. }

 

* This source code was highlighted with Source Code Highlighter.

Лекция 6


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: