.net remoting problem with chat server - c#

I have a problem with my chat server implementation and I couldn't figure out why it doesn't work as intended.
The client could send messages to the server, but the server only sends the messages to itself instead of the client.
E.g. the client connects to the server, then types "hello" into the chat. The server successfully gets the message but then posts the message to its own console instead of sending it to the connected clients.
Well... maybe I have missed something as I'm very new to .Net remoting. Maybe someone could help me figure out what the problem is. Any help is appreciated!
The code:
I have a small interface for the chat implementation on the server
public class ChatService : MarshalByRefObject, IService
{
private Dictionary<string, IClient> m_ConnectedClients = new Dictionary<string, IClient>();
private static ChatService _Chat;
private ChatService()
{
Console.WriteLine("chat service created");
_Chat = this;
}
public bool Login(IClient user)
{
Console.WriteLine("logging in: " + user.GetIp());
if (!m_ConnectedClients.ContainsKey(user.GetIp()))
{
m_ConnectedClients.Add(user.GetIp(), user);
PostMessage(user.GetIp(), user.GetUserName() + " has entered chat");
return true;
}
return false;
}
public bool Logoff(string ip)
{
Console.WriteLine("logging off: " + ip);
IClient user;
if (m_ConnectedClients.TryGetValue(ip, out user))
{
PostMessage(ip, user + " has left chat");
m_ConnectedClients.Remove(ip);
return true;
}
return false;
}
public bool PostMessage(string ip, string text)
{
Console.WriteLine("posting message: " + text + " to: " + m_ConnectedClients.Values.Count);
foreach (var chatter in m_ConnectedClients.Values)
{
Console.WriteLine(chatter.GetUserName() + " : " + chatter.GetIp());
chatter.SendText(text);
}
return true;
}
}
My Server implements the chatservice as singleton:
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ChatService), "chatservice", WellKnownObjectMode.Singleton);
My client is also simply straight forward:
[Serializable]
public class Chat_Client : IClient
{
private string m_IpAdresse;
private string m_UserName = "Jonny";
private string m_Input;
public Chat_Client(string ip, string username)
{
m_IpAdresse = ip;
m_UserName = username;
}
public bool HandleInput(string input)
{
if (input.Equals("exit"))
{
Client.m_ChatService.Logoff(m_IpAdresse);
return false;
}
m_Input = input;
Thread sendThread = new Thread(new ThreadStart(SendPostMessage));
sendThread.Start();
//Console.WriteLine("post message");
return true;
}
private void SendPostMessage()
{
Client.m_ChatService.PostMessage(m_IpAdresse, m_Input);
Thread thisThread = Thread.CurrentThread;
thisThread.Interrupt();
thisThread.Abort();
}
public void SendText(string text)
{
Console.WriteLine("send text got: " + text);
Console.WriteLine(text);
}
The main client connects to the server via:
public void Connect()
{
try
{
TcpChannel channel = new TcpChannel(0);
ChannelServices.RegisterChannel(channel, false);
m_ChatService = (IService)Activator.GetObject(typeof(IService), "tcp://" + hostname + ":9898/Host/chatservice");
System.Net.IPHostEntry hostInfo = Dns.GetHostEntry(Dns.GetHostName());
m_IpAdresse = hostInfo.AddressList[0].ToString();
Chat_Client client = new Chat_Client(m_IpAdresse, m_UserName);
Console.WriteLine("Response from Server: " + m_ChatService.Login(client));
string input = "";
while (m_Running)
{
input = Console.ReadLine();
m_Running = client.HandleInput(input);
}
}
}

#John: No, I wasn't aware of that. Thanks for the info, I'll look into it.
#Felipe: hostname is the dns name of the server I want to connect to.
I found a workaround to make this work. I added an additional TcpListener to the client to which the server connects when the client logs in. Over this second channel I transmit the chat messages back.
However I couldn't understand why the old solution does not work :<
Thanks for the hints guys.

The best thing to do with .NET remoting is to abandon it for WCF. If you read all the best practices for scalability, the way you end up using it is extremely compatible with the Web Services model, and web services is far easier to work with.
Remoting is technically fascinating and forms the basis of reflection, but falls apart once slow, unreliable connections are involved - and all connections are slow and unreliable compared to in-process messaging.

Related

Automatic call to restart a local window service, Privileges issue

I've got a problem with setting the Admin privileges in a propper way; I have already tried ServiceController & ServiceControllerPermission, and it failed, cannot find any solution on the internet which will solve my problem. Code written below:
public class Restarter
{
public string Run(string serviceName)
{
var ctlPrms = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, serviceName);
ctlPrms.Assert();
var srvCtl = new ServiceController(serviceName, Environment.MachineName);
srvCtl.Refresh();
var msg = $"At the beginning, Service: {srvCtl.DisplayName} has status of: {srvCtl.Status}!\n";
if (srvCtl.Status.Equals(ServiceControllerStatus.Running))
{
msg = msg + "Attempting to stop running service\n";
srvCtl.Stop();
srvCtl.WaitForStatus(ServiceControllerStatus.Stopped);
}
else
{
msg = msg + "Attempting to start the service\n";
srvCtl.Start();
srvCtl.WaitForStatus(ServiceControllerStatus.Running);
}
msg = msg + $"At the end, Service: {srvCtl.DisplayName} has status of: {srvCtl.Status}!";
return msg;
}
}
I will be more than gratefull for help with that, I'm already pulling my hair out because of it

Shared resources while using Task.Factory

Here is the code whose responsibility is to connect to the server and get some details.
public class MigrationManager
{
private string referenceServerId;
public void MigrateAnalyzer(string serverid)
{
Gw _Gw = new Gw() // library reference
_Gw.onConnectSucceeded += Handle_OnConnectSucceeded;
_Gw.onConnectFailed += Handle_OnConnectFailed;
ConnectToServer(prxHA, serverid);
}
private void ConnectToServer(string sid)
{
workstationIDForReference = anayzer;
string credentials = GWServiceCredentials("somesecret");
referenceServerId = sid;
_Gw.connectToServer("SSL", "device1-mydomain.net", credentials, referenceServerId);
}
}
This connection operation can end up in two scenarios.
Connection success
Connection failure
These events handled as shown below
private void Handle_OnConnectFailed(int hr)
{
string msg = $"{referenceServerId}";
Console.WriteLine("Connecting to server {0} is failed", msg);
}
private void Handle_OnConnectSucceeded()
{
Console.WriteLine("Connecting to server is success");
}
This works well. Now I am changing it to support multithreading. Because there are multiple requests to connect to the server.
List<string> requestCollection = new List<string>();
requestCollection.Add("I3-1");
requestCollection.Add("I3-2");
requestCollection.Add("I3-3");
var taskList = new List<Task>();
foreach (var serverid in requestCollection )
{
MigrationManager manager = new MigrationManager();
var task = Task.Factory.StartNew(() => manager.MigrateAnalyzer(serverid.ToString()));
}
Task.WaitAll(taskList.ToArray());
I see below Output
Console.WriteLine("Connecting to server I3-1 is failed");
Console.WriteLine("Connecting to server I3-2 is failed");
Console.WriteLine("Connecting to server I3-3 is failed");
Output looks good!
But, I think COM will use shared resources. so how do I use "lock"?

EasyNetQ/RabbitMQ client not getting response in IIS Web Application

I'm using EasyNetQ/RabbitMQ to connect a web application running in IIS to a Windows service. However, I don't seem to get the request/response to work. I pretty sure it's not a code problem but I'm running out of ideas where to look at next.
This is a test console application that works just perfectly:
static void Main()
{
var stopHandle = new ManualResetEventSlim();
var producer = new Thread(() =>
{
string cs = "host=localhost;virtualHost=/;username=demo;password=y4xHEyq3nQOd;timeout=120;persistentMessages=false;prefetchcount=1";
var bus = RabbitHutch.CreateBus(cs, x => x.Register<IEasyNetQLogger>(s => new EasyNetQ.Loggers.ConsoleLogger()));
while (!stopHandle.IsSet)
{
try
{
var result = bus.Request<AutomationRequest, AutomationResponse>(new AutomationRequest
{
taskId = "140061381555",
arguments = "type=pdf",
issueId = 97630548355,
});
Console.WriteLine("Result: " + result.status + ", " + result.status + ", " + result.downloadUrl);
}
catch (Exception)
{
Console.WriteLine("Failed");
}
if (!stopHandle.IsSet) Thread.Sleep(1000);
}
bus.Dispose();
});
producer.Start();
Console.ReadLine();
stopHandle.Set();
producer.Join();
}
}
This on the other hand is the same test code but as a web application:
namespace WebApplication2
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string cs = "host=localhost;virtualHost=/;username=demo;password=y4xHEyq3nQOd;timeout=120;persistentMessages=false;prefetchcount=1";
IBus bus = RabbitHutch.CreateBus(cs, x => x.Register<IEasyNetQLogger>(s => new EasyNetQ.Loggers.ConsoleLogger()));
try
{
var result = bus.Request<AutomationRequest, AutomationResponse>(new AutomationRequest
{
taskId = "140061381555",
arguments = "type=pdf",
issueId = 97630548355,
});
Console.WriteLine("Result: " + result.status + ", " + result.status + ", " + result.downloadUrl);
}
catch (Exception)
{
Console.WriteLine("Failed");
}
bus.Dispose();
}
}
}
Web application sends the message just fine, at queued and it's processed on the back end. Back-end provides the response with the correct correlationID and queues it. However, for some reason unknown to me, the Web application never gets the response.
The Web application eventually gets a timeout. However, the length of the timeout is not the problems, as the getting the response into the queue takes just about two seconds, and changing the timeout to two minutes on both sides does not make any difference.
Does somebody have a ready solution what to fix? Or any ideas where to look? I have googled everything I could figure out about EasyNetQ or RabbitMQ but I didn't even find anybody having reported about similar problems.
--karri

C# as Websocket server for HTML5 websocket connection

I guess it's already time that I ask others. Is it possible to create a websocket server using C# and server request from HTML5 codes?
I am currently using the System package for websocket. I have a code that I downloaded over the internet and here it is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebSocketChatServer
{
using WebSocketServer;
class ChatServer
{
WebSocketServer wss;
List<User> Users = new List<User>();
string unknownName = "john doe";
public ChatServer()
{
// wss = new WebSocketServer(8181, "http://localhost:8080", "ws://localhost:8181/chat");
wss = new WebSocketServer(8080, "http://localhost:8080", "ws://localhost:8080/dotnet/Chats");
wss.Logger = Console.Out;
wss.LogLevel = ServerLogLevel.Subtle;
wss.ClientConnected += new ClientConnectedEventHandler(OnClientConnected);
wss.Start();
KeepAlive();
}
private void KeepAlive()
{
string r = Console.ReadLine();
while (r != "quit")
{
if(r == "users")
{
Console.WriteLine(Users.Count);
}
r = Console.ReadLine();
}
}
void OnClientConnected(WebSocketConnection sender, EventArgs e)
{
Console.WriteLine("test");
Users.Add(new User() { Connection = sender });
sender.Disconnected += new WebSocketDisconnectedEventHandler(OnClientDisconnected);
sender.DataReceived += new DataReceivedEventHandler(OnClientMessage);
}
void OnClientMessage(WebSocketConnection sender, DataReceivedEventArgs e)
{
Console.WriteLine(sender);
User user = Users.Single(a => a.Connection == sender);
if (e.Data.Contains("/nick"))
{
string[] tmpArray = e.Data.Split(new char[] { ' ' });
if (tmpArray.Length > 1)
{
string myNewName = tmpArray[1];
while (Users.Where(a => a.Name == myNewName).Count() != 0)
{
myNewName += "_";
}
if (user.Name != null)
wss.SendToAll("server: '" + user.Name + "' changed name to '" + myNewName + "'");
else
sender.Send("you are now know as '" + myNewName + "'");
user.Name = myNewName;
}
}
else
{
string name = (user.Name == null) ? unknownName : user.Name;
wss.SendToAllExceptOne(name + ": " + e.Data, sender);
sender.Send("me: " + e.Data);
}
}
void OnClientDisconnected(WebSocketConnection sender, EventArgs e)
{
try
{
User user = Users.Single(a => a.Connection == sender);
string name = (user.Name == null) ? unknownName : user.Name;
wss.SendToAll("server: "+name + " disconnected");
Users.Remove(user);
}
catch (Exception exc)
{
Console.WriteLine("ehm...");
}
}
}
}
And I have this code for client side:
<!HTML>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<script language="javascript" type="text/javascript">
jQuery(document).ready(function(){
var socket = new WebSocket("ws://localhost:8080");
socket.onopen = function(){
alert("Socket has been opened!");
}
});
</script>
</head>
</HTML>
As I run my C# console app and load the client page, the app tells me that there's someone who connected in the port it is listening to. But on my client side, as I look in firebug's console, it gives me the beginner's classic error:
Firefox can't establish a connection to the server at ws://localhost:8080/
What I would like to achieve is establish first a successful websocket connection and push value to my client coming from my server.
I have considered Alchemy but the version I have is Visual Studio express 2010, the free version, and it says that "solution folders are not supported in this version of application".
Any help will be very much appreciated.
I've been developing a server for a JavaScript/HTML 5 game for about 7 months now have you looked into Alchemy Websockets? its pretty easy to use.
Example:
using Alchemy;
using Alchemy.Classes;
namespace GameServer
{
static class Program
{
public static readonly ConcurrentDictionary<ClientPeer, bool> OnlineUsers = new ConcurrentDictionary<ClientPeer, bool>();
static void Main(string[] args)
{
var aServer = new WebSocketServer(4530, IPAddress.Any)
{
OnReceive = context => OnReceive(context),
OnConnected = context => OnConnect(context),
OnDisconnect = context => OnDisconnect(context),
TimeOut = new TimeSpan(0, 10, 0),
FlashAccessPolicyEnabled = true
};
}
private static void OnConnect(UserContext context)
{
var client = new ClientPeer(context);
OnlineUsers.TryAdd(client, false);
//Do something with the new client
}
}
}
As you can see its pretty easy to work with and I find their documentation very good (note ClientPeer is a custom class of mine just using it as an example).
What you are trying to achieve will be far easier if you take a look at ASP.NET SignalR
It has support for high level hubs to implement realtime communication and also has a persistent connection low level class to have a finely grained control over the communication.
Support for multiple client types and fallback if websockets isn't supported at both ends of the communication (it can optionally use long polling or forever frames).
The reason for this error is ( probably ) because you are not responding to the handshake. Once the connection is established browser sends some data and the server must respond appropriately ( otherwise browser will close the connection ). You can read more about this on wiki or directly in specification.
I modified a code i downloaded online and here's what I got now:
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
namespace WebSocketServer
{
public enum ServerLogLevel { Nothing, Subtle, Verbose };
public delegate void ClientConnectedEventHandler(WebSocketConnection sender, EventArgs e);
public class WebSocketServer
{
#region private members
private string webSocketOrigin; // location for the protocol handshake
private string webSocketLocation; // location for the protocol handshake
#endregion
static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
static IPEndPoint ipLocal;
public event ClientConnectedEventHandler ClientConnected;
/// <summary>
/// TextWriter used for logging
/// </summary>
public TextWriter Logger { get; set; } // stream used for logging
/// <summary>
/// How much information do you want, the server to post to the stream
/// </summary>
public ServerLogLevel LogLevel = ServerLogLevel.Subtle;
/// <summary>
/// Gets the connections of the server
/// </summary>
public List<WebSocketConnection> Connections { get; private set; }
/// <summary>
/// Gets the listener socket. This socket is used to listen for new client connections
/// </summary>
public Socket ListenerSocker { get; private set; }
/// <summary>
/// Get the port of the server
/// </summary>
public int Port { get; private set; }
public WebSocketServer(int port, string origin, string location)
{
Port = port;
Connections = new List<WebSocketConnection>();
webSocketOrigin = origin;
webSocketLocation = location;
}
/// <summary>
/// Starts the server - making it listen for connections
/// </summary>
public void Start()
{
// create the main server socket, bind it to the local ip address and start listening for clients
ListenerSocker = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
ipLocal = new IPEndPoint(IPAddress.Loopback, Port);
ListenerSocker.Bind(ipLocal);
ListenerSocker.Listen(100);
LogLine(DateTime.Now + "> server stated on " + ListenerSocker.LocalEndPoint, ServerLogLevel.Subtle);
ListenForClients();
}
// look for connecting clients
private void ListenForClients()
{
ListenerSocker.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
private void OnClientConnect(IAsyncResult asyn)
{
byte[] buffer = new byte[1024];
string headerResponse = "";
// create a new socket for the connection
var clientSocket = ListenerSocker.EndAccept(asyn);
var i = clientSocket.Receive(buffer);
headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0, i);
//Console.WriteLine(headerResponse);
if (clientSocket != null)
{
// Console.WriteLine("HEADER RESPONSE:"+headerResponse);
var key = headerResponse.Replace("ey:", "`")
.Split('`')[1] // dGhlIHNhbXBsZSBub25jZQ== \r\n .......
.Replace("\r", "").Split('\n')[0] // dGhlIHNhbXBsZSBub25jZQ==
.Trim();
var test1 = AcceptKey(ref key);
var newLine = "\r\n";
var name = "Charmaine";
var response = "HTTP/1.1 101 Switching Protocols" + newLine
+ "Upgrade: websocket" + newLine
+ "Connection: Upgrade" + newLine
+ "Sec-WebSocket-Accept: " + test1 + newLine + newLine
+ "Testing lang naman po:" + name
;
// which one should I use? none of them fires the onopen method
clientSocket.Send(System.Text.Encoding.UTF8.GetBytes(response));
}
// keep track of the new guy
var clientConnection = new WebSocketConnection(clientSocket);
Connections.Add(clientConnection);
// clientConnection.Disconnected += new WebSocketDisconnectedEventHandler(ClientDisconnected);
Console.WriteLine("New user: " + ipLocal);
// invoke the connection event
if (ClientConnected != null)
ClientConnected(clientConnection, EventArgs.Empty);
if (LogLevel != ServerLogLevel.Nothing)
clientConnection.DataReceived += new DataReceivedEventHandler(DataReceivedFromClient);
// listen for more clients
ListenForClients();
}
void ClientDisconnected(WebSocketConnection sender, EventArgs e)
{
Connections.Remove(sender);
LogLine(DateTime.Now + "> " + sender.ConnectionSocket.LocalEndPoint + " disconnected", ServerLogLevel.Subtle);
}
void DataReceivedFromClient(WebSocketConnection sender, DataReceivedEventArgs e)
{
Log(DateTime.Now + "> data from " + sender.ConnectionSocket.LocalEndPoint, ServerLogLevel.Subtle);
Log(": " + e.Data + "\n" + e.Size + " bytes", ServerLogLevel.Verbose);
LogLine("", ServerLogLevel.Subtle);
}
/// <summary>
/// send a string to all the clients (you spammer!)
/// </summary>
/// <param name="data">the string to send</param>
public void SendToAll(string data)
{
Connections.ForEach(a => a.Send(data));
}
/// <summary>
/// send a string to all the clients except one
/// </summary>
/// <param name="data">the string to send</param>
/// <param name="indifferent">the client that doesn't care</param>
public void SendToAllExceptOne(string data, WebSocketConnection indifferent)
{
foreach (var client in Connections)
{
if (client != indifferent)
client.Send(data);
}
}
/// <summary>
/// Takes care of the initial handshaking between the the client and the server
/// </summary>
private void Log(string str, ServerLogLevel level)
{
if (Logger != null && (int)LogLevel >= (int)level)
{
Logger.Write(str);
}
}
private void LogLine(string str, ServerLogLevel level)
{
Log(str + "\r\n", level);
}
private static string AcceptKey(ref string key)
{
string longKey = key + guid;
byte[] hashBytes = ComputeHash(longKey);
return Convert.ToBase64String(hashBytes);
}
static SHA1 sha1 = SHA1CryptoServiceProvider.Create();
private static byte[] ComputeHash(string str)
{
return sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
}
private void ShakeHands(Socket conn)
{
using (var stream = new NetworkStream(conn))
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
//read handshake from client (no need to actually read it, we know its there):
LogLine("Reading client handshake:", ServerLogLevel.Verbose);
string r = null;
while (r != "")
{
r = reader.ReadLine();
LogLine(r, ServerLogLevel.Verbose);
}
// send handshake to the client
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("WebSocket-Origin: " + webSocketOrigin);
writer.WriteLine("WebSocket-Location: " + webSocketLocation);
writer.WriteLine("");
}
// tell the nerds whats going on
LogLine("Sending handshake:", ServerLogLevel.Verbose);
LogLine("HTTP/1.1 101 Web Socket Protocol Handshake", ServerLogLevel.Verbose);
LogLine("Upgrade: WebSocket", ServerLogLevel.Verbose);
LogLine("Connection: Upgrade", ServerLogLevel.Verbose);
LogLine("WebSocket-Origin: " + webSocketOrigin, ServerLogLevel.Verbose);
LogLine("WebSocket-Location: " + webSocketLocation, ServerLogLevel.Verbose);
LogLine("", ServerLogLevel.Verbose);
LogLine("Started listening to client", ServerLogLevel.Verbose);
//conn.Listen();
}
}
}
Connection issue resolved, next would be SENDING DATA to client.
just change shakehands in WebSocketServer.cs file in solution with below code and your error will gone..
private void ShakeHands(Socket conn)
{
using (var stream = new NetworkStream(conn))
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
//read handshake from client (no need to actually read it, we know its there):
LogLine("Reading client handshake:", ServerLogLevel.Verbose);
string r = null;
Dictionary<string, string> headers = new Dictionary<string, string>();
while (r != "")
{
r = reader.ReadLine();
string[] tokens = r.Split(new char[] { ':' }, 2);
if (!string.IsNullOrWhiteSpace(r) && tokens.Length > 1)
{
headers[tokens[0]] = tokens[1].Trim();
}
LogLine(r, ServerLogLevel.Verbose);
}
//string line = string.Empty;
//while ((line = reader.ReadLine()) != string.Empty)
//{
// string[] tokens = line.Split(new char[] { ':' }, 2);
// if (!string.IsNullOrWhiteSpace(line) && tokens.Length > 1)
// {
// headers[tokens[0]] = tokens[1].Trim();
// }
//}
string responseKey = "";
string key = string.Concat(headers["Sec-WebSocket-Key"], "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
using (SHA1 sha1 = SHA1.Create())
{
byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
responseKey = Convert.ToBase64String(hash);
}
// send handshake to the client
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("WebSocket-Origin: " + webSocketOrigin);
writer.WriteLine("WebSocket-Location: " + webSocketLocation);
//writer.WriteLine("Sec-WebSocket-Protocol: chat");
writer.WriteLine("Sec-WebSocket-Accept: " + responseKey);
writer.WriteLine("");
}
// tell the nerds whats going on
LogLine("Sending handshake:", ServerLogLevel.Verbose);
LogLine("HTTP/1.1 101 Web Socket Protocol Handshake", ServerLogLevel.Verbose);
LogLine("Upgrade: WebSocket", ServerLogLevel.Verbose);
LogLine("Connection: Upgrade", ServerLogLevel.Verbose);
LogLine("WebSocket-Origin: " + webSocketOrigin, ServerLogLevel.Verbose);
LogLine("WebSocket-Location: " + webSocketLocation, ServerLogLevel.Verbose);
LogLine("", ServerLogLevel.Verbose);
LogLine("Started listening to client", ServerLogLevel.Verbose);
//conn.Listen();
}
You may also take a look at the WebSocketRPC library which should be pretty simple to use, for both the "raw" connection and the RPC connections (the messages can also be mixed).
The following can be useful to you:
The code responsible for sending/receiving raw messages is located in the Connection class.
In the repository you can also find how a base JavaScript client is implemented.
Disclaimer: I am the author.

WCF With NetTCP across machines on the same network

I'm trying to implement some cross process communication that is between multiple computers and one server on the same network. What I'm trying right now is to use WCF with NetTcpBinding, hosted within my application which works on the same machine, but when I try to connect from another machine it throws a SSPI security error.
I've found lots of examples of doing this cross-machine, but all involve an app.config file which I would REALLY like to avoid. I want to be able to embed this functionality in a DLL that has not other dependencies (i.e. config files) for which I can just pass into it all of the necessary server addresses, etc and it will work. Is there anyway to setup this security (via the endpoints, etc) purely in code?
I'm testing this all out with the code below:
SERVER:
using System;
using System.ServiceModel;
namespace WCFServer
{
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
public class StringReverser : IStringReverser
{
public string ReverseString(string value)
{
char[] retVal = value.ToCharArray();
int idx = 0;
for (int i = value.Length - 1; i >= 0; i--)
retVal[idx++] = value[i];
string result = new string(retVal);
Console.WriteLine(value + " -> " + result);
return result;
}
}
class Program
{
static void Main(string[] args)
{
var uri = "net.tcp://" + System.Net.Dns.GetHostName() + ":9985";
Console.WriteLine("Opening connection on: " + uri);
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("net.tcp://" + System.Net.Dns.GetHostName() + ":9985")
}))
{
host.AddServiceEndpoint(typeof(IStringReverser),
new NetTcpBinding(),
"TcpReverse");
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
host.Close();
}
}
}
}
CLIENT:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace WCFClient
{
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
class Program
{
static void Main(string[] args)
{
var ep = "net.tcp://SERVER:9985/TcpReverse";
ChannelFactory<IStringReverser> pipeFactory =
new ChannelFactory<IStringReverser>(
new NetTcpBinding(),
new EndpointAddress(
ep));
IStringReverser pipeProxy =
pipeFactory.CreateChannel();
Console.WriteLine("Connected to: " + ep);
while (true)
{
string str = Console.ReadLine();
Console.WriteLine("pipe: " +
pipeProxy.ReverseString(str));
}
}
}
}
Security is normally configured on the binding. You are using NetTcpBinding with its defaults which means that Transport security is enabled.
On both, server and client, you should assign the NetTcpBinding instance to a local variable so that you can change the security (and possibly other) settings, and then use that variable when calling AddServiceEndpoint or when creating the ChannelFactory.
Sample:
var binding = new NetTcpBinding();
// disable security:
binding.Security.Mode = SecurityMode.None;
This is probably an issue with the SPN that your service is running under. It's most likely a machine account instead of a domain account. There's more information in this thread.
UPDATE: There's information in there about setting the SPN programmatically, but it's buried a few clicks in... here's a direct link (see the last section of the page).

Categories

Resources