Может кто-то, пожалуйста, помогите мне с этим ... Я изо всех сил боролся весь день.Проблема с буфером асинхронного чата
Так что я пытаюсь узнать сокеты Async, что-то, что давало мне проблемы.
Вопрос в основном способ, которым я обновляя ListBox с людьми, которые присоединились имена чата в:
В основном то, что я делаю того, чтобы каждый клиент посылает «!! addlist [nickname] ", когда они присоединяются к серверу.
Это не идеальный вариант, поскольку он не проверяет наличие дубликатов и т. Д., Но теперь я просто хочу знать, почему это не сработает. Всякий раз, когда кто-то добавляет имя они не видели раньше, они будут также отправить «!! addlist [ник]»
Таким образом, каждый раз, когда кто-то присоединяется, списки должны быть обновлены для всех. Проблема заключается в том, что все клиенты начинают общаться в одно и то же время, и это мешает буферу.
Я пробовал использовать отдельный буфер для каждого клиента, так что это не проблема. Я пробовал использовать lock(), но это, похоже, не работает.
По существу, происходит то, что буферы, кажется, усекаются; где есть данные от двух разных людей в том же буфере.
Пожалуйста, просто скажи мне, что я делаю неправильно с буферами или на стороне клиента:
Обратите внимание, что сокет асинхронной использует Отправить вместо BeginSend. Я пробовал оба метода, и они сталкиваются с одной проблемой ... так что, вероятно, это клиентская сторона?
public partial class Login : Form
{
private ChatWindow cw;
private Socket serverSocket;
private List<Socket> socketList;
private byte[] buffer;
private bool isHost;
private bool isClosing;
public void startListening()
{
try
{
this.isHost = true; //We're hosting this server
cw.callingForm = this; //Give ChatForm the login form (this) [that acts as the server]
cw.Show(); //Show ChatForm
cw.isHost = true; //Tell ChatForm it is the host (for display purposes)
this.Hide(); //And hide the login form
serverSocket.Bind(new IPEndPoint(IPAddress.Any, int.Parse(portBox.Text))); //Bind to our local address
serverSocket.Listen(1); //And start listening
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); //When someone connects, begin the async callback
cw.connectTo("127.0.0.1", int.Parse(portBox.Text), nicknameBox.Text); //And have ChatForm connect to the server
}
catch (Exception) { /*MessageBox.Show("Error:\n\n" + e.ToString());*/ } //Let us know if we ran into any errors
}
public void AcceptCallback(IAsyncResult AR)
{
try
{
Socket s = serverSocket.EndAccept(AR); //When someone connects, accept the new socket
socketList.Add(s); //Add it to our list of clients
s.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), s); //Begin the async receive method using our buffer
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); //And start accepting new connections
}
catch (Exception) {}
}
public void ReceiveCallback(IAsyncResult AR) //When a message from a client is received
{
try
{
if (isClosing)
return;
Socket s = (Socket)AR.AsyncState; //Get the socket from our IAsyncResult
int received = s.EndReceive(AR); //Read the number of bytes received (*need to add locking code here*)
byte[] dbuf = new byte[received]; //Create a temporary buffer to store just what was received so we don't have extra data
Array.Copy(buffer, dbuf, received); //Copy the received data from our buffer to our temporary buffer
foreach (Socket client in socketList) //For each client that is connected
{
try
{
if (client != (Socket)AR.AsyncState) //If this isn't the same client that just sent a message (*client handles displaying these*)
client.Send(dbuf); //Send the message to the client
}
catch (Exception) { }
} //Start receiving new data again
s.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), s);
}
catch (Exception) { /*cw.output("\n\nError:\n\n" + e.ToString());*/ }
}
public void SendCallback(IAsyncResult AR)
{
try
{
Socket s = (Socket)AR.AsyncState;
s.EndSend(AR);
}
catch (Exception) { /*cw.output("\n\nError:\n\n" + e.ToString());*/ }
}
Вот на стороне клиента:
public void getData()
{
try
{
byte[] buf = new byte[1024];
string message = "";
while(isConnected)
{
Array.Clear(buf, 0, buf.Length);
message = "";
clientSocket.Receive(buf, buf.Length, SocketFlags.None);
message = Encoding.ASCII.GetString(buf);
if (message.StartsWith("!!addlist"))
{
message = message.Replace("!!addlist", "");
string userNick = message.Trim();
if (!namesBox.Items.Contains(userNick))
{
addNick(userNick.Trim());
}
continue;
}
else if (message.StartsWith("!!removelist"))
{
message = message.Replace("!!removelist", "");
string userNick = message.Trim();
removeNick(userNick);
output("Someone left the room: " + userNick);
continue;
}
else if (!namesBox.Items.Contains(message.Substring(0, message.IndexOf(":"))))
{
addNick(message.Substring(0, message.IndexOf(":")).Trim()); //So they at least get added when they send a message
}
output(message);
}
}
catch (Exception)
{
output("\n\nConnection to the server lost.");
isConnected = false;
}
}
Вот моя запаздывающая функция addNick, которая, кажется, чтобы исправить некоторые вещи?
public void addNick(string n)
{
if (n.Contains(" ")) //No Spaces... such a headache
return;
if (n.Contains(":"))
return;
bool shouldAdd = true;
n = n.Trim();
for (int x = namesBox.Items.Count - 1; x >= 0; --x)
if (namesBox.Items[x].ToString().Contains(n))
shouldAdd = false;
if (shouldAdd)
{
namesBox.Items.Add(n);
output("Someone new joined the room: " + n);
sendRaw("!!addlist " + nickName);
}
}
Я думаю, что проблема в том, что некоторые из пакетов пропуска?
Возможно, есть слишком много кода в клиенте после получения, прежде чем он снова будет вызван?
Должен ли я создать отдельный поток для каждого сообщения, чтобы прием выполнялся постоянно? (Dumb)
Должен ли мой клиент использовать Async, он принимает и отправляет?
У меня есть ощущение, что ответ^
Со всеми проверок, которые я делаю, мне удалось очистить дубликат вопрос имени ... но я регулярно получать сообщения с пробелами и частичными сообщениями от других клиентов кажется.
Is getData работает в своей собственной теме? Если это может быть вашей проблемой. Исключение CrossThread, добавляющее материал в ваш список. – Matt
интересный; Я не думал об этом. Да. Должен ли я заблокировать его во время редактирования? У меня регулярно есть несколько потоков, которые записываются в окно сообщения без использования делегатов, хотя и, похоже, он никогда не добавляет лишний текст случайно. – user1274820
@ user1274820 В этом красота неопределенного поведения. Вместо блокировки элемента управления вы должны выполнить доступ в потоке пользовательского интерфейса с помощью 'Control.Invoke()'. – itsme86