SuperWebSocket server can receive only one message - c#

I followed an example at SuperWebSocket discussions to create a tiny web socket server with echo functionality. However, my server can receive and send back only one message, when I try to send second message to it, the connection closes. I use this echo page to test my server.
Here is my code (I use WPF without MVVM here):
public partial class MainWindow : Window
{
private WebSocketServer ws;
public MainWindow()
{
InitializeComponent();
}
private void ConnectButton_Click(object sender, RoutedEventArgs e)
{
var r = new RootConfig();
var s = new ServerConfig();
s.Name = "SuperWebSocket";
s.Ip = "Any";
s.Port = 8089;
s.Mode = SocketMode.Tcp;
var f = new SocketServerFactory();
if (ws != null)
{
ws.Stop();
ws = null;
}
ws = new WebSocketServer();
ws.Setup(r, s, f);
ws.NewMessageReceived += ws_NewMessageReceived;
ws.Start();
}
private void ws_NewMessageReceived(WebSocketSession session, string e)
{
session.Send("Message: " + e);
}
}
I can send messages from the server without problems, but can't receive more than one message without closing the connection. What is the reason of this problem and how do I fix it?

Try replacing:
ws.NewMessageReceived += ws_NewMessageReceived;
with:
ws.NewMessageReceived += new SuperWebSocket.SessionEventHandler<SuperWebSocket.WebSocketSession, string>(ws_NewMessageReceived);

Related

Start SCS server from another class (WinForms)

I'm trying to implement a SCS framework server with WinForms in C# but I am having issues making it work. The server standalone works fine when using it in the Main method (no WinForms). I have a client-sided and a server-sided sample code from the SCS framework that I'm trying to implement in WinForms together with some of my own code. It all went well until I decided to try and use WinForms aswell (I had to move the server code to a class of it's own).
I am not getting any errors when I am starting the server, however I can't connect with the client anymore (worked before I moved the server to a class of its own). Client gets System.Net.Sockets.SocketException. On the server-side, I get the error System.InvalidOperationException when the client is trying to connect.
This is my Form1.cs:
using System;
using System.Windows.Forms;
namespace Server_Test
{
public partial class Form1 : Form
{
public static Form1 Self;
Server server = new Server();
public Form1()
{
InitializeComponent();
Self = this;
}
public void rtb1Text(string text)
{
richTextBox1.AppendText(text);
}
public void rtb2Text(string text)
{
richTextBox2.Text = text;
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text.EndsWith("Start"))
{
button1.Text = "Stop";
server.ServerInit();
}
else if (button1.Text.EndsWith("Stop"))
{
button1.Text = "Start";
// Does nothing atm
}
}
}
}
And this is my Server.cs
using System;
using Hik.Communication.Scs.Communication.EndPoints.Tcp;
using Hik.Communication.Scs.Communication.Messages;
using Hik.Communication.Scs.Server;
namespace Server_Test
{
class Server
{
public void ServerInit()
{
// Create a server that listens 10085 TCP port for incoming connections
var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10085));
// Register events of the server to be informed about clients
server.ClientConnected += Server_ClientConnected;
server.ClientDisconnected += Server_ClientDisconnected;
// Start the server
server.Start();
// Form1.Self.rtb1Text("Server has been started successfully.\n");
Console.WriteLine("Server has been started successfully.\n");
}
static void Server_ClientConnected(object sender, ServerClientEventArgs e)
{
Form1.Self.rtb1Text("A new client with ID: " + e.Client.ClientId + " has connected.\n");
// Register to MessageReceived event to receive messages from new client
e.Client.MessageReceived += Client_MessageReceived;
}
static void Server_ClientDisconnected(object sender, ServerClientEventArgs e)
{
Form1.Self.rtb1Text("A client is disconnected! Client Id = " + e.Client.ClientId + "\n");
}
static async void Client_MessageReceived(object sender, MessageEventArgs e)
{
var message = e.Message as ScsTextMessage; // Server only accepts text messages
if (message == null)
{
return;
}
//Get a reference to the client
var client = (IScsServerClient)sender;
Form1.Self.rtb1Text("Client (ID:" + client.ClientId + ") sent a request: " + message.Text + "\n");
switch (message.Text)
{
case "api":
HttpPost httpPost = new HttpPost();
var apiResponse = await httpPost.SendPost("robot_info");
//Send reply message to the client
client.SendMessage(
new ScsTextMessage(
apiResponse,
message.MessageId //Set first message's id as replied message id
));
break;
default:
break;
}
}
}
}
My guess is that I'm doing something wrong when creating a new instance of the Server class and how I'm initializing/starting the server. Might be something else though, I've tried debugging but it didn't make me any smarter.
Any ideas?

Facing Issues in WinForm Integration with my Existing Azure Bot Using Directline API

I have created a bot using Bot Framework SDK (C#, .Net). I have published it in Azure. It is working fine in WebChat as well as in Teams channel. Now I want to create one Winform and trying to connect the Winform UI to my bot using Directline Api.
This is my code :
public partial class Form1 : Form
{
private static string directLineSecret = ConfigurationSettings.AppSettings["DirectLineSecret"];
private static string botId = ConfigurationSettings.AppSettings["BotId"];
private static string fromUser = "User";
private static string id = "default-user";
private Conversation conversation;
DirectLineClient directLineClient = null;
public Form1()
{
InitializeComponent();
InitClientAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private async Task InitClientAsync()
{
directLineClient = new DirectLineClient($"{directLineSecret}");
directLineClient.BaseUri = new Uri($"https://directline.botframework.com/");
//directLineClient = new DirectLineClient(directLineSecret);
conversation = await directLineClient.Conversations.StartConversationAsync().ConfigureAwait(false);
new System.Threading.Thread(async () => await ReadBotMessageAsync(directLineClient, conversation.ConversationId)).Start();
}
private async Task ReadBotMessageAsync(DirectLineClient client, string conversationId)
{
string watermark = null;
while(true)
{
var activitySet = await client.Conversations.GetActivitiesAsync(conversationId, watermark);
watermark = activitySet?.Watermark;
var activities = from x in activitySet.Activities where x.From.Id == botId select x;
foreach(Activity activity in activities)
{
if(activity.Text != null)
{
string message = activity.Text;
if(InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate
{
textBox.AppendText("Bot : " + message + "\r\n");
}));
}
}
}
}
}
private async void btn_Send_Click(object sender, EventArgs e)
{
string input = txt_Send.Text;
txt_Send.Clear();
if(input.Length>0)
{
Activity userMessage = new Activity
{
From = new ChannelAccount(id, fromUser),
Text = input,
Type = ActivityTypes.Message,
TextFormat = "plain"
};
textBox.AppendText("You : " + input + "\r\n");
await directLineClient.Conversations.PostActivityAsync(this.conversation.ConversationId, userMessage);
}
}
}
But when I execute the program it is stopping due to Null reference exception when it is trying to get conversation as well as conversation Id.
you can check the error image here.
Can anyone please tell me what I'm missing here?
Any help will be appreciated.....
The problem was with the directline secret key. I regenerate a new key and used it. Now that is starting the conversation and I am able to see conversation Id.
But after that I was getting status code 429 error. That is basically Multiple thread issue. It is trying to create multiple threads at the same time.
Then I recreate the whole project with .Net Framework version 4.6.2 (Previously using 4.7). Now that issue also got resolved. Project is working fine.

C# handler not creating and failing when using .CreateHandler()

I'm creating a game in which I use TCP/IP connection. The problem is that I'm using .Invoke to help me receive and send message.
The program goes like this: I'm my first window, i'm starting and connecting to the server like this :
{
TcpListener listener = new TcpListener(IPAddress.Any, this.port);
listener.Start();
try {
this.client = listener.AcceptTcpClient();
gameWindow = new GameWindow(this.client, true);
gameWindow.StartGame();
}
}
then i'm connecting to it like this:
{
IPEndPoint ipEnd = new IPEndPoint(this.serverIP, this.port);
{
try {
client.Connect(ipEnd);
if (client.Connected) {
gameWindow = new GameWindow(this.client, false);
gameWindow.StartGame();
}
}
}
The constructor for gameWindow (which is a form) looks like this:
public GameWindow(TcpClient thisClient, bool isServer)
{
InitializeComponent();
this.client = thisClient;
this.reader = new StreamReader(thisClient.GetStream());
this.writer = new StreamWriter(thisClient.GetStream());
this.writer.AutoFlush = true;
}
I must wait for the server to send a message to the client, and then start the client ( I have a function .startGame() that uses .ShowDialog() and creates some pictureBoxs)
But nowhere I can get my handle created. I've tried to put this.createHandle() (read about it here) into GameWindow_Load but still not works. If I try to send a message with:
workerSendData.RunWorkerAsync(); I get:
Additional information: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
What can I do to get my handler created? Using Thread.Sleep will sleep my whole UI, which does not work (a "solution" found on the internet)
My code for sending message :
private void workerSendData_DoWork(object sender, DoWorkEventArgs e)
{
if (client.Connected) {
this.writer.WriteLine(this.toSend); // aici trimitem datele.
// de modificat : aici vom adauga in lista noastra miscarile.
this.Invoke(new MethodInvoker(delegate () { MessageBox.Show("Me:" + this.toSend + "\n"); }));
}
else {
MessageBox.Show("Send failed");
}
workerSendData.CancelAsync();
}
My code for receiving data:
private void workerReceiveData_DoWork(object sender, DoWorkEventArgs e)
{
while (client.Connected) {
try {
this.received = this.reader.ReadLine();
this.myTurn = true;
this.Invoke(new MethodInvoker(delegate () {
MessageBox.Show("This has been received: " + this.received);
/*this.tbReceive.AppendText("You:" + this.received + "\n");*/
}));
this.received = "";
}
catch (Exception x) {
MessageBox.Show(x.Message.ToString());
}
}
}
It seems that you cannot invoke an action before the Window is fully initialized and loaded. Assuming you are working in Windows Forms, there is a solution provided by #Greg D on this question, but it doesn't be to be the safest way to go.
I would suggest that you try to find a way to start the worker only after the window is loaded (for example using the Loaded event), so that the handle is definitely ready and this situation does not occur.

connect to other computer that is not local

I try to connect from my pc to other pc what I have at home and both are connected to the internet. So I check the other pc with the program MyIpAdress and it is like: 38.xx.xx.xx.
And I have this program:The server:
public delegate void StatusChangedHandler(object sender, StatusChangedEventArgs e);
public class StatusChangedEventArgs : EventArgs
{
// This will store our only parameter / event argument, which is the event message
private string EventMsg;
// We need to define this property in order to retrieve the message in the event handler, back in Form1.cs
public string EventMessage
{
get
{
return EventMsg;
}
}
// The constructor will set the message
public StatusChangedEventArgs(string strEventMsg)
{
EventMsg = strEventMsg;
}
}
class Monitor
{
// Will store the IP address passed to it
IPAddress ipAddress;
// The constructor sets the IP address to the one retrieved by the instantiating object
public Monitor(IPAddress address)
{
ipAddress = address;
}
// Declare the event that we'll fire later
public event StatusChangedHandler StatusChangedEvent;
// The thread that will hold the connection listener
private Thread thrListener;
// The TCP object that listens for connections
private TcpListener tlsServer;
// The thread that will send information to the client
private Thread thrSender;
// Will tell the while loop to keep monitoring for connections
bool ServRunning = false;
public void StartMonitoring()
{
// Get the IP of the first network device, however this can prove unreliable on certain configurations
IPAddress ipaLocal = ipAddress;
if (tlsServer == null)
{
// Create the TCP listener object using the IP of the server and the specified port
tlsServer = new TcpListener(ipaLocal, 1986 );
}
// Start the TCP listener and listen for connections
tlsServer.Start();
// The while loop will check for true in this before checking for connections
ServRunning = true;
// Start the new tread that hosts the listener
thrListener = new Thread(KeepListening);
thrListener.Start();
}
private void KeepListening()
{
TcpClient tclServer;
// While the server is running
while (ServRunning == true)
{
// Accept a pending connection
tclServer = tlsServer.AcceptTcpClient();
// Start a new thread where our new client who just connected will be managed
thrSender = new Thread(new ParameterizedThreadStart(AcceptClient));
// The thread calls the AcceptClient() method
thrSender.Start(tclServer);
}
}
// Occures when a new client is accepted
private void AcceptClient(object newClient)
{
// Set the argument/parameter to a message explaining what just happened
StatusChangedEventArgs evArg = new StatusChangedEventArgs("A client was successfully accepted.");
// Fire the event because a new client was accepted
StatusChangedEvent(this, evArg);
}
}
But if I fill in in the textbox the ipadress: 38.xxx.xxx.xx,
I will get this error:
An unhandled exception of type 'System.Net.Sockets.SocketException'
occurred in System.dll
Additional information: The requested address is not valid in its context
So it can only see Local ipAdresses?
But how to change it, that it also finds not local Ipadresses?
And this is the client application:
public partial class Form1 : Form
{
private string UserName = "Unknown";
private StreamWriter swSender;
private StreamReader srReceiver;
private TcpClient tcpServer;
// Needed to update the form with messages from another thread
private delegate void UpdateLogCallback(string strMessage);
// Needed to set the form to a "disconnected" state from another thread
private delegate void CloseConnectionCallback(string strReason);
private Thread thrMessaging;
private IPAddress ipAddr;
private bool Connected;
public Form1()
{
Application.ApplicationExit += new EventHandler(OnApplicationExit);
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// If we are not currently connected but awaiting to connect
if (Connected == false)
{
// Initialize the connection
InitializeConnection();
}
else // We are connected, thus disconnect
{
CloseConnection("Disconnected at user's request.");
}
}
private void ReceiveMessages()
{
// Receive the response from the server
srReceiver = new StreamReader(tcpServer.GetStream());
// If the first character of the response is 1, connection was successful
string ConResponse = srReceiver.ReadLine();
// If the first character is a 1, connection was successful
if (ConResponse[0] == '1')
{
// Update the form to tell it we are now connected
this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { "Connected Successfully!" });
}
else // If the first character is not a 1 (probably a 0), the connection was unsuccessful
{
string Reason = "Not Connected: ";
// Extract the reason out of the response message. The reason starts at the 3rd character
Reason += ConResponse.Substring(2, ConResponse.Length - 2);
// Update the form with the reason why we couldn't connect
this.Invoke(new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });
// Exit the method
return;
}
// While we are successfully connected, read incoming lines from the server
while (Connected)
{
// Show the messages in the log TextBox
this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
}
}
private void InitializeConnection()
{
// Parse the IP address from the TextBox into an IPAddress object
ipAddr = IPAddress.Parse(txtServerIP.Text);
// Start a new TCP connections to the chat server
tcpServer = new TcpClient();
tcpServer.Connect(IPAddress.Any, 1986);
// Helps us track whether we're connected or not
Connected = true;
// Prepare the form
UserName = txtUserName.Text;
// Disable and enable the appropriate fields
txtServerIP.Enabled = false;
txtUserName.Enabled = false;
txtMessage.Enabled = true;
btnSend.Enabled = true;
btnConnect.Text = "Disconnect";
// Send the desired username to the server
swSender = new StreamWriter(tcpServer.GetStream());
swSender.WriteLine(txtUserName.Text);
swSender.Flush();
// Start the thread for receiving messages and further communication
thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
thrMessaging.Start();
}
private void UpdateLog(string strMessage)
{
// Append text also scrolls the TextBox to the bottom each time
txtLog.AppendText(strMessage + "\r\n");
}
private void btnSend_Click(object sender, EventArgs e)
{
SendMessage();
}
private void SendMessage()
{
if (txtMessage.Lines.Length >= 1)
{
swSender.WriteLine(txtMessage.Text);
swSender.Flush();
txtMessage.Lines = null;
}
txtMessage.Text = "";
}
// Closes a current connection
private void CloseConnection(string Reason)
{
// Show the reason why the connection is ending
txtLog.AppendText(Reason + "\r\n");
// Enable and disable the appropriate controls on the form
txtServerIP.Enabled = true;
txtUserName.Enabled = true;
txtMessage.Enabled = false;
btnSend.Enabled = false;
btnConnect.Text = "Connect";
// Close the objects
Connected = false;
swSender.Close();
srReceiver.Close();
tcpServer.Close();
}
public void OnApplicationExit(object sender, EventArgs e)
{
if (Connected == true)
{
// Closes the connections, streams, etc.
Connected = false;
swSender.Close();
srReceiver.Close();
tcpServer.Close();
}
}
}
So I changed this line:
tcpServer.Connect(IPAddress.Any, 1986);
but If I run the server application I will get this error:
I get the same error as by the client:
An unhandled exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
Additional information: The requested address is not valid in its context
Thank you
I show you two Images:This is the Server app. That works
This is the Client app, that doesnt work:
And if I change the code in the client app, like this:
tcpServer.Connect(ipAddr, 1986); Then I will get this error:
Additional information: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
But I can pin the other pc
In the client program I have this:
private void InitializeConnection()
{
// Parse the IP address from the TextBox into an IPAddress object
ipAddr = IPAddress.Parse(txtServerIP.Text);
// Start a new TCP connections to the chat server
tcpServer = new TcpClient();
tcpServer.Connect(IPAddress.Any, 1986);
// Helps us track whether we're connected or not
Connected = true;
// Prepare the form
UserName = txtUserName.Text;
// Disable and enable the appropriate fields
txtServerIP.Enabled = false;
txtUserName.Enabled = false;
txtMessage.Enabled = true;
btnSend.Enabled = true;
btnConnect.Text = "Disconnect";
// Send the desired username to the server
swSender = new StreamWriter(tcpServer.GetStream());
swSender.WriteLine(txtUserName.Text);
swSender.Flush();
// Start the thread for receiving messages and further communication
thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
thrMessaging.Start();
}
what I have to change then?
Maybe you have to allow TCP connections on your port in the firewall for the applications on both PCs. Make sure that connections from and to the network are allowed.

How to get access to form's controls from class C#

I've got problem when I am trying to get access to form's controls from another class. My program is hanging in infinite loop. I know why, but I don't know how to write this correctly.
Here is Form1.cs (to my Form)
public Form1()
{
InitializeComponent();
Load config = new Load();
string[] data = config.readConfig("config.ini");
if (data.Length == 4) { //client
Client run = new Client();
run.startClient(data[1], Convert.ToInt32(data[2]));
}
else if (data.Length == 3) //server
{
Server run = new Server();
run.startServer(Convert.ToInt32(data[1]));
}
}
public void addLog(string dataLog){
richTextBox1.Text += dataLog;
}
and here is Client.cs file:
class Client
{
public void startClient(string ipAddr, int port)
{
Form1 form1 = new Form1();
TcpClient client = new TcpClient();
try
{
form1.addLog("Connecting...");
client.Connect(ipAddr, port);
form1.addLog("Connected to server: " + ipAddr + ":" + port.ToString());
}
catch
{
MessageBox.Show("We couldn't connect to server");
}
}
}
How can I change text value without running each time new form. Maybe There is something like run_once?
The infinite loop is here:
Form1:
//Always runs if the config file is a certain length
Client run = new Client();
Client:
Form1 form1 = new Form1();
Each constructor creates the other object, which in turn creates the first object, ad infintum.
If you need to get the form object to the client don't create a new one!. It doesn't work anyways, as your new form object knows nothing about the old one. Just pass it in:
public Client(Form1 form)
{
//Do whatever with it
}
//Form class
Client c = new Client(this);
Disclaimer: There are usually far better ways to do this, but you'll learn those as you get more familiar with design patterns/architecture.

Categories

Resources