Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/41: Рейтинг темы: голосов - 41, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 03.12.2013
Сообщений: 2

TCP чат-сервер

03.12.2013, 20:32. Показов 8066. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте! Нужна помощь с таким заданием: На базе шаблона параллельного эхо-сервера, использующего модель “один клиент - один поток”, разработать чат-сервер для обмена текстовыми сообщениями между произвольным количеством узлов. Модифицировать шаблон клиента для работы с чат-сервером. Использовать протокол TCP.
Шаблоны приведены ниже:
Сервер
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
 * Шаблон параллельного эхо-сервера TCP, работающего по модели
 * "один клиент - один поток".
 *
 * Компиляция:
 *  cc -Wall -O2 -pthread -o server3 server3.c
 */
 
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
 
/*
 * Конфигурация сервера.
 */
#define PORT 1027
#define BACKLOG 5
#define MAXLINE 256
 
#define SA struct sockaddr
 
/*
 * Обработчик фатальных ошибок.
 */
void error(const char *s)
{
    perror(s);
    exit(-1);
}
 
/*
 * Функции-обертки.
 */
int Socket(int domain, int type, int protocol)
{
    int rc;
    
    rc = socket(domain, type, protocol);
    if(rc == -1) error("socket()");
 
    return rc;
}
 
int Bind(int socket, struct sockaddr *addr, socklen_t addrlen)
{
    int rc;
    
    rc = bind(socket, addr, addrlen);
    if(rc == -1) error("bind()");
 
    return rc;
}
 
int Listen(int socket, int backlog)
{
    int rc;
    
    rc = listen(socket, backlog);
    if(rc == -1) error("listen()");
 
    return rc;
}
 
int Accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
{
    int rc;
    
    for(;;) {
        rc = accept(socket, addr, addrlen);
        if(rc != -1) break;
        if(errno == EINTR || errno == ECONNABORTED) continue;
        error("accept()");
    }       
 
    return rc;  
}
 
void Close(int fd)
{
    int rc;
    
    for(;;) {
        rc = close(fd);
        if(!rc) break;
        if(errno == EINTR) continue;
        error("close()");
    }
}
 
size_t Read(int fd, void *buf, size_t count)
{
    ssize_t rc;
    
    for(;;) {
        rc = read(fd, buf, count);
        if(rc != -1) break;
        if(errno == EINTR) continue;
        error("read()");
    }
    
    return rc;
}
 
size_t Write(int fd, const void *buf, size_t count)
{
    ssize_t rc;
    
    for(;;) {
        rc = write(fd, buf, count);
        if(rc != -1) break;
        if(errno == EINTR) continue;
        error("write()");
    }
    
    return rc;
}
 
void *Malloc(size_t size)
{
    void *rc;
    
    rc = malloc(size);
    if(rc == NULL) error("malloc()");
    
    return rc;
}
 
void Pthread_create(pthread_t *thread, pthread_attr_t *attr,
    void *(*start_routine)(void *), void *arg)
{
    int rc;
    
    rc = pthread_create(thread, attr, start_routine, arg);
    if(rc) {
        errno = rc;
        error("pthread_create()");
    }
}
 
/*
 * Чтение строки из сокета.
 */
size_t reads(int socket, char *s, size_t size)
{
    char *p;
    size_t n, rc;
    
    /* Проверить корректность переданных аргументов. */
    if(s == NULL) {
        errno = EFAULT;
        error("reads()");
    }
    if(!size) return 0;
 
    p = s;
    size--;
    n = 0;
    while(n < size) {
        rc = Read(socket, p, 1);
        if(rc == 0) break;
        if(*p == '\n') {
            p++;
            n++;
            break;
        }
        p++;
        n++;
    }
    *p = 0;
    
    return n;
}
 
/*
 * Запись count байтов в сокет.
 */
size_t writen(int socket, const char *buf, size_t count)
{
    const char *p;
    size_t n, rc;
 
    /* Проверить корректность переданных аргументов. */
    if(buf == NULL) {
        errno = EFAULT;
        error("writen()");
    }
    
    p = buf;
    n = count;
    while(n) {
        rc = Write(socket, p, n);
        n -= rc;
        p += rc;
    }
 
    return count;
}
 
void *serve_client(void *arg)
{
    int socket;
    char s[MAXLINE];
    ssize_t rc;
    
    /* Перевести поток в отсоединенное (detached) состояние. */
    pthread_detach(pthread_self());
 
    socket = *((int *) arg);
    free(arg);
 
    while((rc = reads(socket, s, MAXLINE)) > 0) {
        if(writen(socket, s, rc) == -1) break;
    }
    Close(socket);
 
    return NULL;
}
 
int main(void)
{
    int lsocket;    /* Дескриптор прослушиваемого сокета. */
    int csocket;    /* Дескриптор присоединенного сокета. */
    struct sockaddr_in servaddr;
    int *arg;
    pthread_t thread;
        
    /* Создать сокет. */
    lsocket = Socket(PF_INET, SOCK_STREAM, 0);
 
    /* Инициализировать структуру адреса сокета сервера. */
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    /* Связать сокет с локальным адресом протокола. */
    Bind(lsocket, (SA *) &servaddr, sizeof(servaddr));
 
    /* Преобразовать неприсоединенный сокет в пассивный. */
    Listen(lsocket, BACKLOG);
            
    for(;;) {
        csocket = Accept(lsocket, NULL, 0);
 
        arg = Malloc(sizeof(int));
        *arg = csocket;
        
        Pthread_create(&thread, NULL, serve_client, arg);
    }
    
    return 0;
}
Клиент
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
 * Шаблон TCP клиента.
 *
 * Компиляция:
 *  cc -Wall -O2 -o client client.c
 *
 * Завершение работы клиента: Ctrl+D.
 */
 
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
 
#include <limits.h>
 
#define MAX(a, b) ((a) > (b) ? (a) : (b))
 
#define PORT 1027
#define MAXLINE 256
 
#define SA struct sockaddr 
 
/*
 * Обработчик фатальных ошибок.
 */
void error(const char *s)
{
    perror(s);
    exit(-1);
}   
 
/*
 * Функции-обертки.
 */
int Socket(int domain, int type, int protocol)
{
    int rc;
    
    rc = socket(domain, type, protocol);
    if(rc == -1) error("socket()");
 
    return rc;
}
 
void Connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
{
    int rc;
    
    rc = connect(socket, addr, addrlen);
    if(rc == -1) error("connect()");
}
 
void Close(int fd)
{
    int rc;
    
    for(;;) {
        rc = close(fd);
        if(!rc) break;
        if(errno == EINTR) continue;
        error("close()");
    }
}
 
void Inet_aton(const char *str, struct in_addr *addr)
{
    int rc;
    
    rc = inet_aton(str, addr);
    if(!rc) {
        /* Функция inet_aton() не меняет errno в случае ошибки. Чтобы
        сообщение, выводимое error(), было более осмысленным,
        присваиваем errno значение EINVAL. */
                
        errno = EINVAL;
        error("inet_aton()");
    }
}
 
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
    struct timeval *timeout)
{
    int rc;
    
    for(;;) {
        rc = select(n, readfds, writefds, exceptfds, timeout);
        if(rc != -1) break;
        if(rc == EINTR) continue;
        error("select()");
    }
    
    return rc;
}
 
size_t Read(int fd, void *buf, size_t count)
{
    ssize_t rc;
    
    for(;;) {
        rc = read(fd, buf, count);
        if(rc != -1) break;
        if(errno == EINTR) continue;
        error("read()");
    }
    
    return rc;
}
 
size_t Write(int fd, const void *buf, size_t count)
{
    ssize_t rc;
    
    for(;;) {
        rc = write(fd, buf, count);
        if(rc != -1) break;
        if(errno == EINTR) continue;
        error("write()");
    }
    
    return rc;
}
 
/*
 * Запись count байтов в сокет.
 */
size_t writen(int socket, const char *buf, size_t count)
{
    const char *p;
    size_t n, rc;
 
    /* Проверить корректность переданных аргументов. */
    if(buf == NULL) {
        errno = EFAULT;
        error("writen()");
    }
    
    p = buf;
    n = count;
    while(n) {
        rc = Write(socket, p, n);
        n -= rc;
        p += rc;
    }
 
    return count;
}
 
void show_usage()
{
    puts("Usage: client ip_address");   
    exit(-1);
}
 
void do_work(int socket)
{
    int n;
    fd_set readfds;
    char s[MAXLINE];
    ssize_t rc;
 
    n = MAX(STDIN_FILENO, socket) + 1;  
            
    for(;;) {
        /* Инициализировать набор дескрипторов. */
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(socket, &readfds);
 
        Select(n, &readfds, NULL, NULL, NULL);
        if(FD_ISSET(STDIN_FILENO, &readfds)) {
            rc = Read(STDIN_FILENO, s, MAXLINE);
            if(!rc) break;
            writen(socket, s, rc);
        }
        if(FD_ISSET(socket, &readfds)) {
            rc = Read(socket, s, MAXLINE);
            if(!rc) break;
            Write(STDOUT_FILENO, s, rc);
        }
    }
}
 
int main(int argc, char **argv)
{
    int socket;
    struct sockaddr_in servaddr;
    
    if(argc != 2) show_usage();
 
    socket = Socket(PF_INET, SOCK_STREAM, 0);
    
    /* Инициализировать структуру адреса сокета. */
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    Inet_aton(argv[1], &servaddr.sin_addr);
 
    Connect(socket, (SA *) &servaddr, sizeof(servaddr));
    do_work(socket);        
    Close(socket);
    
    return 0;
}
После компиляции данных шаблонов выяснилось, что работает это всё как эхо-сервер, т.е. клиент вводит строку и получает её же.

Вопрос, что нужно добавить/изменить в сервере и в клиенте?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.12.2013, 20:32
Ответы с готовыми решениями:

Простой чат-сервер.
Вообщем есть задание написать чат сервер на 2 и более клиентов... Начал знакомиться с сокетами, решил использовать стратегию fork(); ...

tcp сервер linux-windows
Здравствуйте, дали задание- написать на С# сервер на linux,который бы отправлял любое сообщение клиенту и клиент на windows который отвечал...

Чат (Сервер|Клиент) с UDP протоколом
Всем Привет, вообщем задача написать простенький чат c использованием UDP протокола. Для начала я написал эхо-сервер (1 сервер - 1...

2
 Аватар для Ullaluna
8 / 6 / 5
Регистрация: 11.11.2013
Сообщений: 75
04.12.2013, 01:19
Вопрос, что нужно добавить/изменить в сервере и в клиенте?
Думаю, что-то вроде динамического списка. Добавить в сервер.

Вам надо, чтобы сервер переслал сообщение всем клиентам, кроме клиента - автора сообщения. Клиенты характеризуются файловыми дескрипторами. Тогда. Создаем список, добавляем туда каждого клиента под своим fd, и когда от номера пятого приходит сообщение, рассылаем его всем по списку, исключая номер пятый.

C++
1
2
3
4
for (int i = 0; i < listlength; i++) {
    if (listmember(i) != fd) {
        rc = write(fd, buf, count);
        ...
1
0 / 0 / 0
Регистрация: 03.12.2013
Сообщений: 2
05.12.2013, 12:51  [ТС]
Спасибо огромное. Заработало
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
05.12.2013, 12:51
Помогаю со студенческими работами здесь

TCP/IP сервер - клиент - как работать с потоками?
Доброго времени суток, друзья. Пытаюсь создать локальный чат по типу клиент-сервер по протоколу tcp/ip. Имеется большая проблема с...

Клиент-сервер TCP для Linux с fork
Помогите написать клиент серверную программу TCP для Linux с fork. Демонстрация должна быть такая: к серверу подключается несколько...

Простенький сервер работающий по протоколу TCP/IP, на основе сокетов
добрый день, уважаемые программисты. так и атк - дали задание, делаем - нужно мне было написать простенький сервер работающий по...

Чат TCP Консоль сервер + WinForm клиент
Чат TCP сервер консоль + WinForm клиент Есть код где Консоль сервер+ Консоль клиент создает Чат но когда это я перевел на Консоль...

Tcp чат. Не коннектится с другими или роняет сервер
помогите исправить, на одном компе запускается , при конекте с другим не цепляется либо серв падает.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru