PDA

Просмотр полной версии : XMLSocket и сервер на C#


kostasoft
30.05.2007, 23:46
Простой клиент во флеше на AS2:
import flash.net;
import flash.events;
_global.sock = new XMLSocket();
sock.onConnect = function(success) {
if (success)
textBox1.text = "Статус: Подключен";
else
textBox1.text = "Статус: Отключен";
};
sock.onClose = function() {
textBox1.text = "Статус: Закрыт сервером";
};
sock.onXML = function(XMLtext) {
trace("onXML"+XMLtext);
};
sock.onData = function(XMLdata) {
trace("onData"+XMLdata);
};
btConnect.onRelease=function(){
sock.connect("oxy",8087);
}
btClose.onRelease=function(){
sock.close();
textBox1.text = "Статус: Закрыт пользователем";
}
btSend.onRelease=function(){
sock.send("sended");
}
и сервер на C# на ассинхронном сокете,
консольное приложение Program.cs:
using System;
using System.Collections.Generic;
using System.Text;
using kostasoft;

namespace MultiSocketDemo
{
class Program
{
static void Main(string[] args)
{
serverSoket sock = new serverSoket(8087);
sock.Start();
Console.ReadLine();
}
}
}
Класс для работы с сокетами serverSoket.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;


namespace kostasoft
{
class serverSoket
{
private Socket _serverSocket;
private int _port;
private List<ConnectionInfo> _connections = new List<ConnectionInfo>();
private class ConnectionInfo
{
public Socket Socket;
public byte[] Buffer;
}

public serverSoket(int port)
{
_port = port;
}

private void SetupServerSocket()
{
// Получаем информацию о локальном компьютере
IPHostEntry localMachineInfo =
Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint myEndpoint = new IPEndPoint(
localMachineInfo.AddressList[0], _port);

Console.WriteLine("Запускаем сервер на ip: " + localMachineInfo.AddressList[0].ToString() + ":" + _port.ToString());
// Создаем сокет, привязываем его к адресу
// и начинаем прослушивание
_serverSocket = new Socket( myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(myEndpoint);
_serverSocket.Listen((int) SocketOptionName.MaxConnections);
}

public void Start()
{
SetupServerSocket();
for (int i = 0; i < 10; i++)
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}

private void AcceptCallback(IAsyncResult result)
{
ConnectionInfo connection = new ConnectionInfo();
try
{
// Завершение операции Accept
Socket s = (Socket)result.AsyncState;
connection.Socket = s.EndAccept(result);
connection.Buffer = new byte[255];
lock (_connections) _connections.Add(connection);
// Начало операции Receive и новой операции Accept
connection.Socket.BeginReceive(connection.Buffer,
0, connection.Buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback),
connection);
_serverSocket.BeginAccept(new AsyncCallback(
AcceptCallback), result.AsyncState);
}
catch (SocketException exc)
{
CloseConnection(connection);
Console.WriteLine("Socket exception: " +
exc.SocketErrorCode);
}
catch (Exception exc)
{
CloseConnection(connection);
Console.WriteLine("Exception: " + exc);
}
}

private void ReceiveCallback(IAsyncResult result)
{
ConnectionInfo connection =
(ConnectionInfo)result.AsyncState;
try
{
int bytesRead =
connection.Socket.EndReceive(result);
if (0 != bytesRead)
{
string readData = Encoding.UTF8.GetString(connection.Buffer, 0, bytesRead);
string writeData = "ansver\u000A\u0000";
readData = readData.Substring(0, bytesRead-1);
Console.WriteLine(readData);

Console.WriteLine(writeData);
byte[] msg = Encoding.UTF8.GetBytes(writeData);
lock (_connections)
{
foreach (ConnectionInfo conn in
_connections)
{
if (connection != conn)
{
conn.Socket.Send(msg, msg.Length, 0);//SocketFlags.None);
}
}
}
connection.Socket.BeginReceive(
connection.Buffer, 0,
connection.Buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback),
connection);
}
else CloseConnection(connection);
}
catch (SocketException exc)
{
CloseConnection(connection);
Console.WriteLine("Socket exception: " +
exc.SocketErrorCode);
}
catch (Exception exc)
{
CloseConnection(connection);
Console.WriteLine("Exception: " + exc);
}
}

private void CloseConnection(ConnectionInfo ci)
{
ci.Socket.Close();
lock (_connections) _connections.Remove(ci);
}
}
}
Проблема: клиент передает данные серверу, сервер их получает, в ответ отсылает строку клиенту, а в клиенте не вызывается событие onData или onXML. Отсылаемую строку заканчиваю 0. В чем может быть трабла?
ЗЫ: Асинхронный сокет в таком виде использую, т.к. он наиболее быстрый при большом кол-ве коннектов.

kostasoft
31.05.2007, 11:56
К ночи тупить начал...:D
Код, приведеный выше для сервера отсылает сообщение, принятое от одного клиента, всем другим подключеным клиентам. Чтобы он отправлял тому же клиенту, надо отправлять в этом же коннекшене. Короче, функция ReceiveCallback должна быть такая:
private void ReceiveCallback(IAsyncResult result)
{
ConnectionInfo connection =
(ConnectionInfo)result.AsyncState;
try
{
int bytesRead = connection.Socket.EndReceive(result);
if (0 != bytesRead)
{
string readData = Encoding.UTF8.GetString(connection.Buffer, 0, bytesRead);
readData = readData.Substring(0, bytesRead-1);
Console.WriteLine(readData);

string writeData = "ansver\u0000";
Console.WriteLine(writeData);
byte[] msg = Encoding.UTF8.GetBytes(writeData);
connection.Socket.Send(msg, msg.Length, SocketFlags.None);
connection.Socket.BeginReceive(
connection.Buffer, 0,
connection.Buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback),
connection);
}
else CloseConnection(connection);
}
catch (SocketException exc)
{
CloseConnection(connection);
Console.WriteLine("Socket exception: " +
exc.SocketErrorCode);
}
catch (Exception exc)
{
CloseConnection(connection);
Console.WriteLine("Exception: " + exc);
}
}

etc
31.05.2007, 12:21
Во флеше клиент не на AS2, а на AS1. И flash.events нет в AS2/AS1, а в пакете flash.net есть только FileReference, не относящийся к сокетами совершенно никак. Т.е. два импорта нафиг не нужны.

kostasoft
03.06.2007, 00:38
Спасибо, учту. Я больше по сям, флешь ковырять жизнь заставила (уж больно красивый клиент можно забацать, c# отдыхает, тем более для других платформ).
В догонку еще вопрос нарисовался (опять ближе к ночи :D ) :
Какую строку должен передать сервер клиенту на запрос о политике безопасности по тому же порту, по которому будет дальнейшая работа (в моем случае 8087)? Нужно, чтоб клиент работал не только из прожекта, но и загруженый из html или запущеный как swf. (Для линукса, например, есть адобовский плеер).
Я так понимаю, строка должна содержать xml, но точные данные для моего случая не могу подобрать.

kostasoft
03.06.2007, 13:20
Сам себе ночью пишу и сам себе же утром отвечаю...
В serverSocket.cs добавляем:

private const string policyRequest = "<policy-file-request/>";
...
if (recData.IndexOf(policyRequest) != -1)
{
data = "<?xml version=\"1.0\"?>";
data += "<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">";
data += "<cross-domain-policy>";
data += "<allow-access-from domain=\"*\" to-ports=\"*\" />";
data += "</cross-domain-policy>\u0000";
}
, где recData - принятые данные
data - отправляемые данные

Осталось разобраться с полноэкранным режимом клиента на флеше, если грузим его из html. Использую в Publish setting на вкладке html опцию template как Flash Only - Allow Full Screen. В тексте программы пишу:
fscommand("fullscreen", true);
fscommand("showmenu", false);
Для прожекта работает на полный экран, для html - нет!
IDE - Flash CS3

etc
04.06.2007, 04:50
Мммм… так и не должно работать (слава богу). Правда, в девятой (9,0,28,0) версии плеера появилось свойство displayState у Stage.
http://livedocs.adobe.com/flash/9.0/main/00002149.html

kostasoft
04.06.2007, 15:33
Изменил на
Stage.displayState = "fullscreen";
Stage.showMenu = false;
Все равно не пашет, хотя для прожекта работало как и с фскомандами...
В хтмл и в жаваскрипте все поменялось автоматически, когда выставил Allow Full Screen...

etc
04.06.2007, 15:42
А версия плеера-то какая?

kostasoft
04.06.2007, 19:06
9.0.45.0

etc
04.06.2007, 19:33
Мммм, попробуй разместить все на хосте и оттуда посмотреть.

kostasoft
04.06.2007, 22:07
От туда и смотрю. Сервак аппач. под винду, правда, но это пофиг. Может из-за эксплорера (7,0,5730,11)? Но вроде из-по оперы тоже смотрел, не раскрывается. И вспомнил, под этим эксплорером смотрел демку, с сайта, она раскрывалась на полный экран.
Может из-за того, что Stage.displayState стоит в первом кадре application-a? Попробую кнопарь сбацать с переключением из нормала в фул...

Получилось! Из евента нажатия батона заработало! А из 1 кадра не хотело. Буду думать, как сделать автоматический запуск в полноэкранном режиме. _etc - спасибо!

billy bones
08.07.2007, 07:10
У меня часто сервер начинает бесконечно принимать нулевое сообщение с клиента после закрытия соединения с клиентом. Знает ли кто нибудь какой сигнал подает флэш клиент для закрытия соединения и какое событие на сервере этот сигнал инициирует?

LOLFlash
11.07.2007, 07:30
http://www.adobe.com/devnet/flashplayer/articles/full_screen_mode.html