Задача - создать кроссплатформенный клиент-сервер протокол.
Функционал серверной части реализованы на 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