Здравствуйте!
У меня не получается написать клиент-серверное приложение на протоколе UDP с использованием Socket.
Я пытаюсь построить UDP приложение на подобие приложение на протоколе TCP(P.S. Код TCP клиент серверного приложения частично состоит из примеров находящихся в открытом доступе), а работает оно у меня так:
СЕРВЕР:
1) Есть поток1(стоковый в котором работает метод Main).
Метод Mainclass Program
{
static ServerObject server; // Сервер
static Thread listenThread; // Поток для прослушивания
static void Main(string[] args)
{
try
{
server = new ServerObject();
listenThread = new Thread(new ThreadStart(server.Listen));
listenThread.Start(); // Старт потока
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
2) Запускается поток2 в котором начинается ожидание подключений.
Метод Listenprotected internal void Listen()
{
try
{
tcpListener = new TcpListener(IPAddress.Any, 34447);
tcpListener.Start();
Console.WriteLine("Сервер запущен. Ожидайте подключений...");
while(true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
ClientObject clientObject = new ClientObject(tcpClient, this);
Thread clientThread = new Thread(new ThreadStart(clientObject.Process));
clientThread.Start();
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
3) После подключения клиента к серверу, сервер сохраняет клиента в классе и запускает поток3 для получения сообщений от клиента и рассылки его другим клиентам после в классе ServerObject в список List<> сохраняется ClientObject:
Конструктор класса ClientObjectprotected internal string Id { get; private set; }
protected internal NetworkStream Stream { get; private set; }
string userName;
TcpClient client;
ServerObject server;
public ClientObject(TcpClient tcpClient, ServerObject serverObject)
{
Id = Guid.NewGuid().ToString();
client = tcpClient;
server = serverObject;
serverObject.AddConnection(this);
}
Метод Process в классе ClientObjectpublic void Process()
{
try
{
Stream = client.GetStream();
// Получаем имя пользователя
string message = GetMessage();
userName = message;
while(true)
{
try
{
message = GetMessage();
message = String.Format("{0}: {1}", userName, message);
Console.WriteLine(message);
server.BroadcastMessage(message, this.Id);
}
catch
{
break;
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
Метод AddConnection в классе ServerObjectList<ClientObject> clients = new List<ClientObject>(); // Все подключения
protected internal void AddConnection(ClientObject clientObject)
{
clients.Add(clientObject);
}
4)При получении сообщения от пользователя вызывается метод BroadcastMessage из класса ServerObject, в котором полученное сообщение рассылается всем подключенным клиентам кроме самого отправителя, а информация кому отправлять содержится в списке List<> clients:
Метод BroadcastMessage в классе ServerObjectprotected internal void BroadcastMessage(string message, string id)
{
byte[] data = Encoding.Unicode.GetBytes(message);
for(int i = 0; i < clients.Count; i++)
{
if (clients[i].Id != id)
clients[i].Stream.Write(data, 0, data.Length);
}
}
КЛИЕНТ НА UNITY:
Clientstring userName;
private const string host = "127.0.0.1";
private const int port = 34447;
public TcpClient client;
public NetworkStream stream;
public Text messages;
public Text outPut;
void Start()
{
Connection();
}
public void Connection()
{
userName = "login";
client = new TcpClient();
try
{
client.Connect(host, port); // Подключение клиента
stream = client.GetStream(); // Получаем поток
byte[] data = Encoding.Unicode.GetBytes(userName);
stream.Write(data, 0, data.Length);
// Запускаем новый поток для получения данных
Thread receiveThread = new Thread(new ThreadStart(ReceiveMessage));
receiveThread.Start();
outPut.text += "Добро пожаловать, " + StaticHelperScripts.login + "\n";
}
catch(Exception ex)
{
Debug.Log(ex.Message);
}
}
public void SendMessage()
{
outPut.GetComponent<Text>().text += userName + " : " + messages.text + "\n";
byte[] data = Encoding.Unicode.GetBytes(messages.text);
stream.Write(data, 0, data.Length);
}
// получение сообщений
public void ReceiveMessage()
{
while (true)
{
try
{
byte[] data = new byte[512]; // буфер для получаемых данных
StringBuilder builder = new StringBuilder();
int bytes = 0;
do
{
bytes = stream.Read(data, 0, data.Length);
builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
}
while (stream.DataAvailable == false && bytes == 0);
string message = builder.ToString();
outPut.text += message + "\n";
}
catch(Exception ex)
{
outPut.text += "Подключение прервано!\n"; //соединение было прервано
Disconnect();
return;
}
}
}
public void Disconnect()
{
if (stream != null)
stream.Close(); // Отключение потока
if (client != null)
client.Close(); // отключение клиента
}
Теперь собственно вопрос что необходимо сохранять чтобы сделать список из подключенных клиентов и делать рассылку сообщений от других клиентов? Я понимаю что протокол UDP без установления соединения поэтому я не могу понять как сделать подобное приложение только на UDP. А так же мультиплеерных action(шутеры) играх используется протокол UDP, т.к. он благополучно влияет на ping который очень важен. Вопрос: Что бы отправить сообщение по UDP должен быть открыт порт что не есть хорошо(к примеру 1к игроков и укаждого должен быть открыт порт 34447)?
Мне к сожалению трудно дается протокол UDP, так что прошу прощения за возможную банальщину.
P.S. Попытался расписать все максимально подробно, если что то не понятно задавайте вопросы, а я отвечу вам на них(если смогу). И всем огромное спасибо за всеее!!!