Форум программистов, компьютерный форум, киберфорум
Наши страницы
Delphi и сети
Войти
Регистрация
Восстановить пароль
 
 
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
#1

Чат на сокетах - Delphi

02.09.2016, 15:37. Просмотров 871. Ответов 30
Метки нет (Все метки)

Здрасьте.
Знаю, что тема до невозможности бородатая, но возникла необходимость создания программы для чата, и при ее создании возникли некоторые сложности. А именно - не приходят сообщения от клиента к серверу.
От сервера идут, а обратно не хотят.
Клиент и сервер реализованы в одной программе (так нужно).

Вот код:
Delphi
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
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ScktComp;
 
type
  TForm1 = class(TForm)
    ClientSocket: TClientSocket;
    ServerSocket: TServerSocket;
    portedit: TEdit;
    lblport: TLabel;
    IP: TLabel;
    Hostedit: TEdit;
    Nik: TLabel;
    NikEdit: TEdit;
    txtlbl: TLabel;
    TextEdit: TEdit;
    ChatMemo: TMemo;
    SendBtn: TButton;
    ServerBtn: TButton;
    ClientBtn: TButton;
 
    procedure FormCreate(Sender: TObject);
 
    procedure ServerBtnClick(Sender: TObject);
    procedure ServerSocketClientConnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketClientDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
 
    procedure SendBtnClick(Sender: TObject);
    procedure ClientBtnClick(Sender: TObject);
    procedure ClientSocketRead(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ClientSocketConnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ClientSocketDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketAccept(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocketConnecting(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocketClientError(Sender: TObject;
      Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
      var ErrorCode: Integer);
 
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
 
//ЗАПОЛНЕНИЕ ПОЛЕЙ
procedure TForm1.FormCreate(Sender: TObject);
begin
PortEdit.Text:='50000';
HostEdit.Text:='192.168.0.100';
 
NikEdit.Clear;
TextEdit.Clear;
ChatMemo.Lines.Clear;
end;
 
 
//СЕРВЕР
procedure TForm1.ServerBtnClick(Sender: TObject);
begin
If ServerBtn.Tag=0 then
Begin
ClientBtn.Enabled:=False;
HostEdit.Enabled:=False;
PortEdit.Enabled:=False;
 
ServerSocket.Port:=StrToInt(PortEdit.Text);
ServerSocket.Active:=True;
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Сервер создан');
ServerBtn.Tag:=1;
ServerBtn.Caption:='Закрыть сервер';
end
else
Begin
ClientBtn.Enabled:=True;
HostEdit.Enabled:=True;
PortEdit.Enabled:=True;
 
ServerSocket.Active:=False;
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Сервер закрыт.');
ServerBtn.Tag:=0;
ServerBtn.Caption:='Создать сервер';
end;
end;
 
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add(Socket.ReceiveText);
end;
 
procedure TForm1.ServerSocketClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Подключился клиент.');
end;
 
procedure TForm1.ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Клиент отключился.');
end;
 
procedure TForm1.ServerSocketAccept(Sender: TObject;
  Socket: TCustomWinSocket);
begin
 ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Подключился клиент.');
end;
 
procedure TForm1.ServerSocketClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Ошибка.');
end;
 
 
 
//КЛИЕНТ
procedure TForm1.ClientBtnClick(Sender: TObject);
begin
If ClientBtn.Tag=0 then
Begin
 
ServerBtn.Enabled:=False;
HostEdit.Enabled:=False;
PortEdit.Enabled:=False;
 
ClientSocket.Port:=StrToInt(PortEdit.Text);
ClientSocket.Host:=HostEdit.Text;
ClientSocket.Address:=HostEdit.Text;
ClientSocket.Active:=True;
 
ClientBtn.Tag:=1;
ClientBtn.Caption:='Отключиться';
end
else
Begin
ServerBtn.Enabled:=True;
HostEdit.Enabled:=True;
PortEdit.Enabled:=True;
 
ClientSocket.Active:=False;
ClientBtn.Tag:=0;
ClientBtn.Caption:='Подключиться';
end;
end;
 
procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add(Socket.ReceiveText);
end;
 
procedure TForm1.ClientSocketConnecting(Sender: TObject;
  Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Подключение к серверу.');
end;
 
procedure TForm1.ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Успешно.');
end;
 
procedure TForm1.ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] Сеанс завершен.');
end;
 
 
 
//ОТПРАВКА СООБЩЕНИЯ
procedure TForm1.SendBtnClick(Sender: TObject);
begin
If ServerSocket.Active=True then
begin
ServerSocket.Socket.Connections[0].SendText('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
end
else
begin
ClientSocket.Socket.SendText('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
end;
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
TextEdit.Text:='';
end;
 
end.
Предполагаю, что проблема кроется либо здесь:
Delphi
106
107
108
109
110
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add(Socket.ReceiveText);
end;
либо тут:
Delphi
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//ОТПРАВКА СООБЩЕНИЯ
procedure TForm1.SendBtnClick(Sender: TObject);
begin
If ServerSocket.Active=True then
begin
ServerSocket.Socket.Connections[0].SendText('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
end
else
begin
ClientSocket.Socket.SendText('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
end;
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
TextEdit.Text:='';
end;
Ах да.. я тут новичок. Да и в программировании тоже тот еще ламер. Так что прошу сильно не ругать
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.09.2016, 15:37
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Чат на сокетах (Delphi):

Чат на сокетах
Здравствуйте, форумчане. Сейчас занялся написанием чата на сокетах. Всё вроде...

Чат на сокетах (Нюанс)
Здраствуйте. Сделал клиент,сервер на сокетах, на одном компе они работают- это...

Сделать чат на сокетах
дал клиент другу(у меня сервер), мы используем одинаковый интернет от 1...

Переадресация на сокетах
Добрый день уважаемые программисты. Суть дела такова: Есть клиент и сервер....

Соединение на сокетах
можно ли на сокетах созадть программу которая будет соединяться по интернету с...

Регистрация/авторизация на сокетах
Как с помощью компонентов TServerSocket и TClientSocket организовать...

30
Shuma_256
7 / 7 / 3
Регистрация: 08.02.2016
Сообщений: 89
02.09.2016, 20:24 #2
Проблема в том, что сервер не слушает твои сокеты, ты сразу с них хочешь принимать, тебе нужно в сервере сделать метод OnExecute и там прописать принятие сообщений
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
02.09.2016, 22:53  [ТС] #3
Что-то не наблюдаю такого ивента..
Или не здесь?
0
Изображения
 
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
05.09.2016, 18:01  [ТС] #4
Поможет кто?..
0
Fulcrum_013
Заблокирован
05.09.2016, 18:31 #5
Цитата Сообщение от artivad2 Посмотреть сообщение
От сервера идут, а обратно не хотят.
А их что кто то обратно посылает?
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
06.09.2016, 00:08  [ТС] #6
Fulcrum_013, да, естественно я их посылаю
0
Fulcrum_013
Заблокирован
06.09.2016, 07:06 #7
artivad2 Да вот в том то и дело что не вижу чтобы серверный сокет что то отправлял.
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
07.09.2016, 02:33  [ТС] #8
Fulcrum_013, так вот же оно
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure TForm1.SendBtnClick(Sender: TObject);
begin
If ServerSocket.Active=True then
begin
ServerSocket.Socket.Connections[0].SendText('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');//Отправка от сервера
end
else
begin
ClientSocket.Socket.SendText('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');//Отправка от клиента
end;
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
TextEdit.Text:='';
end;
0
Fulcrum_013
Заблокирован
07.09.2016, 08:28 #9
artivad2, Проверь события у ClientSocket. ну что ClientSocketRead действительно ему на OnRead назначено.
Если назначено попробуй из серверного отправлять всем коннекциям а не только нулевой.
0
San22Rus
14 / 14 / 8
Регистрация: 07.03.2016
Сообщений: 152
07.09.2016, 12:55 #10
artivad2, вот посмотри может что и найдёшь полезное, когда то давно писал чат, только у меня сервер отдельно
0
Вложения
Тип файла: rar Чат.rar (8.88 Мб, 18 просмотров)
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
07.09.2016, 23:47  [ТС] #11
Fulcrum_013,
Delphi
1
2
3
4
5
procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add(Socket.ReceiveText);
end;
Delphi
1
2
3
4
5
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
ChatMemo.Lines.Add(Socket.ReceiveText);
end;
Обе процедуры прописаны в OnRead и OnClientRead соответственно.

San22Rus, ух.. сложно чёт. У меня есть чей-то чат в котором сервер и клиент разделены. И он работает как надо. И единственная существенная разница в том, что сервер, получая сообщение от клиента тут же отправляет его дальше, другим клиентам, а не выводит в мемо как у меня.
Вот как это работает там:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
procedure TForm1.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
S: String;
X: Integer;
begin
S:=Socket.ReceiveText;
//если это прислан ник
If copy(S,1,5)='Nick=' then
begin
  //добавляем в список
 Users.Add(copy(S,6,Length(S)-5));
 end;
//если это сообщение
if copy(S,1,5)='mess=' then
  begin
  //то рассылаем
  for X:=0 to Users.Count-1 do
    Server.Socket.Connections[x].SendText(S);
  end;
end;
Есть список юзеров, чего нет у меня. И я думал, что проблема в Server.Socket.Connections[x].SendText так как у меня 0 вместо х. Но.. сообщение от сервера то приходит по этой команде - вот в чем дело.
А отправка со стороны клиента устроена так же как и у меня, только 'mess=' добавляется в начале сообщения
0
Fulcrum_013
Заблокирован
08.09.2016, 08:22 #12
Цитата Сообщение от artivad2 Посмотреть сообщение
Но.. сообщение от сервера то приходит по этой команде - вот в чем дело.
Правильно. В событие передается указатель на коннекцию по которой оно пришло. А при передаче отправляешь по нулевой которая вообще может быть для мебели.
У меня примерно вот так и все пашет:
C++
1
2
3
4
5
6
7
8
9
10
11
12
void __fastcall TForm1::ServerClientRead(TObject* Sender,   TCustomWinSocket *Socket){
      AnsiString Text=Socket->ReceiveText();
      Echo(Text);// получаем и выводим текст
      // и рассылаем всем остальным клиентам
      for(int i=0;i<ServerSocket->Socket->ActiveConnections;i++)
          if (ServerSocket->Socket->Connections[i]!=Socket) ServerSocket->Socket->Connections[i]->SendText(Text);
};  
void __fastcall TForm1::Send(AnsiString Text){ 
// это вызывается при необходимости отправить текст клиентам со стороны сервера
      for(int i=0;i<ServerSocket->Socket->ActiveConnections;i++)
          ServerSocket->Socket->Connections[i]->SendText(Text);
};
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
08.09.2016, 16:32  [ТС] #13
Fulcrum_013, тааак..
Исправил код, как ты написал. Получилась вот такая финтифлюха:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Кнопка отправки сообщения:
procedure TForm1.SendBtnClick(Sender: TObject);
var
X: Integer;
begin
If ServerSocket.Active=True then
begin
for X := 0 to ServerSocket.Socket.ActiveConnections-1 do
    ServerSocket.Socket.Connections[X].SendText(''+NikEdit.Text+': '+TextEdit.Text+'');
end
else
begin
ClientSocket.Socket.SendText(''+NikEdit.Text+': '+TextEdit.Text+'');
end;
ChatMemo.Lines.Add('['+TimeToStr(Time)+'] '+NikEdit.Text+': '+TextEdit.Text+'');
TextEdit.Text:='';
end;
Delphi
1
2
3
4
5
6
7
8
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
X: Integer;
begin
for X := 0 to ServerSocket.Socket.ActiveConnections-1 do
    ServerSocket.Socket.Connections[X].SendText(Socket.ReceiveText);
end;
И всё равно отправляется только клиенту черт его дери..
Зато можно нескольким слать, спасибо за это
Но проблема всё ещё висит..
0
Fulcrum_013
Заблокирован
08.09.2016, 20:08 #14
artivad2, Поставь на ClientSocket.Socket.SendText(''+NikEdit.Text+': '+TextEdit.Text+''); точку останова и посмотри он туда вообще приходит или нет.

Добавлено через 2 минуты
Цитата Сообщение от artivad2 Посмотреть сообщение
TForm1.ServerSocketClientRead
Да кстати, отправить его по всем коннекциям ты отправил. а выводить его кто будет? У серверного сокета коннекции самого к себе нет.
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
08.09.2016, 20:50  [ТС] #15
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Поставь на ClientSocket.Socket.SendText(''+NikEdit.Text+': '+TextEdit.Text+''); точку останова и посмотри он туда вообще приходит или нет.
Ась? Что для этого сделать?

Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Да кстати, отправить его по всем коннекциям ты отправил. а выводить его кто будет? У серверного сокета коннекции самого к себе нет.
Delphi
1
2
3
4
5
6
7
8
9
10
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
X: Integer;
begin
for X := 0 to ServerSocket.Socket.ActiveConnections-1 do
    ServerSocket.Socket.Connections[X].SendText(Socket.ReceiveText);
 
ChatMemo.Lines.Add(TimeToStr(Time)+' '+Socket.ReceiveText);
end;
Так? Всё равно не приходит..
0
Fulcrum_013
Заблокирован
09.09.2016, 13:13 #16
Цитата Сообщение от artivad2 Посмотреть сообщение
Ась? Что для этого сделать?
Брекпоинт поставь. Ткни мышью в бордюр слева от кода чтобы там красный кружек появился. Потом запусти через F8 он на первой комаде остановится. Дальше через F9 запусти. Если управление доходит до точки останова он на ней остановится.
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
10.09.2016, 00:34  [ТС] #17
Fulcrum_013, Проверил. Галочка загорается. Приходит стало быть.
0
Fulcrum_013
Заблокирован
10.09.2016, 12:53 #18
Цитата Сообщение от artivad2 Посмотреть сообщение
Проверил. Галочка загорается. Приходит стало быть.
Теперь точно так же проверь вызывается ли TForm1.ClientSocketRead
0
artivad2
0 / 0 / 0
Регистрация: 09.06.2013
Сообщений: 29
10.09.2016, 17:54  [ТС] #19
Fulcrum_013, тоже выполняется.
Но клиент то читает, в этом дело. А сервер нет
0
Fulcrum_013
Заблокирован
10.09.2016, 18:00 #20
НУ тогда у сервера тоже ,брек-поинтом проверь приходит туда управление или нет
т.е. посавь бряк в ServerSocketClientRead;
Только похоже ошибка видна сразу:
Delphi
1
2
3
for X := 0 to ServerSocket.Socket.ActiveConnections-1 do
    ServerSocket.Socket.Connections[X].SendText(Socket.ReceiveText);
ChatMemo.Lines.Add(TimeToStr(Time)+' '+Socket.ReceiveText);
У тебя текст один раз пришел а прочитать ты его пытаешься ServerSocket.Socket.ActiveConnections+1 раз. При повторном чтении буфер пуст и сокет ждет пока в него что то не пришлют. Прочитай его в переменную а потом уже переменную рассылай и выводи. ReceiveText это не переменная (свойство), а функция, которая осуществляет чтение следующей строки из сокета.
0
10.09.2016, 18:00
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.09.2016, 18:00
Привет! Вот еще темы с решениями:

Возможность отправки папки с файлами по локальной сети, сеть создана на сокетах
Здравствуйте уважаемые форумчане, помогите пожалуйста, у меня есть программа,...

Тестирование на сокетах. Можно ли как-то выделить вопрос-ответ в отдельную функцию?
Хотелось бы узнать следующее... Есть сервер-сокет, и есть клиент-сокет. Если...

чат
Здравствуйте форумчане и модераторы! У меня КП. Почти всё сделано правильно,...

чат
В общим есть клиент-программы. В нем есть чат мне надо, с него брать данные и...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru