I'm trying to create a Websocket server using SuperSocket library but documentation is limited and I can't find any info on how to setup & configure a websocket server.
My key requirements are:
Create the Server in code.
Setup multiple listeners
Provide custom setting for number of worker/pool threads.
server = new WebSocketServer();
var serverConfig = new SuperSocket.SocketBase.Config.ServerConfig();
serverConfig.MaxConnectionNumber = 100000;
//serverConfig.Port = 222;
//serverConfig.ListenBacklog = 5000;
var list = new List<SuperSocket.SocketBase.Config.ListenerConfig>(20);
int port = 223;
for (int i = 0; i < 1;i++)
{
var listener = new SuperSocket.SocketBase.Config.ListenerConfig();
listener.Port = port;
listener.Backlog = 1000;
listener.Ip = "Any";
listener.Security = "None";
port++;
list.Add(listener);
}
serverConfig.Listeners = list;
server.Setup(serverConfig);
server.NewSessionConnected += server_NewSessionConnected;
server.SessionClosed += server_SessionClosed;
server.NewMessageReceived += server_NewMessageReceived;
server.Start();
I tried following code but it result in following error "You cannot start a server instance which has not been setup yet". However, if I comment out the for loop and uncomment the two lines above it then it works, although it only listens on one port.
Just for the sake of others coming to this unanswered question. The OP does have the method nearly correct, maybe capacity declaration is interfering, not sure, didn't play with it, but with a slight change to the listener creation, it works.
var list = new List<SuperSocket.SocketBase.Config.ListenerConfig>();
int port = 223;
for (int i = 0; i < 21;i++)
{
var listener = new SuperSocket.SocketBase.Config.ListenerConfig();
listener.Port = port;
port++;
list.Add(listener);
}
Related
I'd like to peek all messages from several Azure Service Bus queues. After that I want to filter them after queueName, insertDate and give the opportunity to make a full text search on the body.
Currently, I'm using the Microsoft.Azure.ServiceBus package to create a ManagementClient for gathering queue information and then use a MessageReceiver to peek the messages.
var managementClient = new ManagementClient(connectionString);
var queue = await managementClient.GetQueueRuntimeInfoAsync(queueName);
var count = queue.MessageCount;
var receiver = new MessageReceiver(connectionString, queueName);
var messagesOfQueue = new List<Message>();
for (var i = 1; i <= count; i++)
{
messagesOfQueue.Add(await receiver.PeekAsync());
}
Is there a better way to get all messages? Or is there even a way to only peek messages that apply to a filter?
I've also tried to use the QueueClient.PeekBatch Method from the WindowsAzure.ServiceBus package. But that method didn't return all messages although I've set the correct messageCount parameter.
And then there is also the package Azure.Messaging.ServiceBus... What's up with all these packages?
So which of the packages should I use and what is the best way for peeking messages of queues based on some filters?
The solution I'm currently using and which works as expected looks like this:
var receiver = serviceBusClient.CreateReceiver(queueName);
var messagesOfQueue = new List<ServiceBusReceivedMessage>();
var previousSequenceNumber = -1L;
var sequenceNumber = 0L;
do
{
var messageBatch = await receiver.PeekMessagesAsync(int.MaxValue, sequenceNumber);
if (messageBatch.Count > 0)
{
sequenceNumber = messageBatch[^1].SequenceNumber;
if (sequenceNumber == previousSequenceNumber)
break;
messagesOfQueue.AddRange(messageBatch);
previousSequenceNumber = sequenceNumber;
}
else
{
break;
}
} while (true);
It uses the nuget package Azure.Messaging.ServiceBus.
Currently you're receiving a single message from the receiver. A better option would be to receive messages in batch using PeekBatchAsync(Int64, Int32) method of MessageReceiver.
Here's the sample code to do so (untested though):
var messagesOfQueue = new List<Message>();
var sequenceNumber = 0;
var batchSize = 100;//number of messages to receive in a single call
do
{
var messages = await receiver.PeekBatchAsync(sequenceNumber, batchSize);
messagesOfQueue.AddRange(messages);
if (messages.Count > 0)
{
sequenceNumber = messages[messages.Count-1].SequenceNumber;
}
else
{
break;
}
} while (true);
The solution avoids getting the message with the same SequenceNumber twice.
Sequence numbers monotonically increase. And I've tested most cases except rolling over sequenceNumber to 0 when it reaches the maximum value (Long.MaxValue).
using Azure.Messaging.ServiceBus;
private static async Task<List<ServiceBusReceivedMessage>> PeekAllMessages(string serviceBusConnectionString, string queueName)
{
var client = new ServiceBusClient(serviceBusConnectionString);
var receiver = client.CreateReceiver(queueName);
var messages = new List<ServiceBusReceivedMessage>();
var batchSize = 20;
var sequenceNumber = 0L;
do
{
var messageBatch = await receiver.PeekMessagesAsync(batchSize, sequenceNumber);
if (messageBatch.Count <= 0)
{
break;
}
// Increasing the SequenceNumber by 1 to avoid getting the message with the same SequenceNumber twice
sequenceNumber = messageBatch[^1].SequenceNumber + 1;
messages.AddRange(messageBatch);
} while (true);
return messages;
}
According the documentation, a gRPC client is created from a channel. Multiple concrete gRPC clients can be created from a channel, including different types of clients, but I didn't find any information about concurrency.
So, my question, Can I use the channel for concurrent calls like below?
var channel = GrpcChannel.ForAddress("https://localhost:5001");
// the first task
Task.Run(() => {
var client = new Greet.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + response.Message);
});
// the second task
Task.Run(() => {
var client = new Greet.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + response.Message);
});
Or I need to create own channel for each thread(task).
As #Mike has noted, The GrpcChannel is using HttpClient under the hood. So, according this, we probably can create a single http client and reuse it throughout the life of an application.
HttpClient is intended to be instantiated once and re-used throughout the life of an application.
I have built a simple example to investigate the area.
GRPS service:
public class GreeterService
: Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
//Server side handler of the SayHello RPC
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
_logger.LogInformation($"Sending hello to {request.Name}");
Thread.Sleep(500);
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
The single channel for all threads
string uri = $"https://localhost:5001";
var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions()
{
HttpClient = HttpClientFactory.Create(),
DisposeHttpClient = true
});
int threadCount = 6;
Thread[] threads = new Thread[threadCount];
for(int i = 0; i < threadCount; ++i)
{
threads[i] = new Thread((index) =>
{
Console.WriteLine($"Thread({(int)index}) has been started!");
for (int req = 0; req < 75; ++req)
{
var client = new Greeter.GreeterClient(channel);
client.SayHello(new HelloRequest()
{
Name = $"Thread {(int)index}"
});
}
Console.WriteLine($"Thread({(int)index}) has been finished!");
});
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Start(i);
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Join();
}
Own channel for each thread
string uri = $"https://localhost:5001";
int threadCount = 6;
Thread[] threads = new Thread[threadCount];
for(int i = 0; i < threadCount; ++i)
{
threads[i] = new Thread((index) =>
{
var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions()
{
HttpClient = HttpClientFactory.Create(),
DisposeHttpClient = true
});
Console.WriteLine($"Thread({(int)index}) has been started!");
for (int req = 0; req < 75; ++req)
{
var client = new Greeter.GreeterClient(channel);
client.SayHello(new HelloRequest()
{
Name = $"Thread {(int)index}"
});
}
Console.WriteLine($"Thread({(int)index}) has been finished!");
});
}
Thread.Sleep(1000 * 10);
for (int i = 0; i < threadCount; ++i)
{
threads[i].Start(i);
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Join();
}
Summary, I can make a conclusion that we can create a single GRPC channel and reuse it in the app. But I don't know how effective using one channel for many request is
i see that the question is answered but I wanted to add that there are sections in docs about client concurrency. If someone new read this question i hope this will be helpful.
Microsoft docs
Introduction to gRPC on .NET Core
Chapter "Reuse gRPC channels" on gRPC - Performance and practices.
Channels are safe to share and reuse between gRPC calls:
gRPC clients are created with channels. gRPC clients are lightweight objects and don't need to be cached or reused.
Multiple gRPC clients can be created from a channel, including different types of clients.
A channel and clients created from the channel can safely be used by multiple threads.
Clients created from the channel can make multiple simultaneous calls.
"Connection concurrency" chapter on this topic is also very helpful.
NOTE: Look topic Configuration for configuring services and client channels.
gRPC API Documentation
Namespace Grpc.Net.Client
GrpcChannel
Represents a gRPC channel. Channels are an abstraction of long-lived
connections to remote servers. Client objects can reuse the same
channel. Creating a channel is an expensive operation compared to
invoking a remote call so in general you should reuse a single channel
for as many calls as possible.
gRPC Documentation
There are no specifics about client concurrency, but Core concepts topic is also very helpful by giving glimpses on how gRPC works underhood.
I'm trying to upgrade a server / client (player) application on windows forms to deal with a multiplayer environment (4 players) as part of an assignment for my coding course, using tcplistener and tcpclient. I'm relatively new to coding, especially on such complex topics. I hope I'm going on the right track for this.
I've been researching extensively lately so, by now, I think I have a good idea on the meaning and differences of threading and asynchronous execution. My main problem is on implementing it and getting it to work.
So, I started by working on the code provided on class (with some minor changes), it's working on a server player scenario (server side):
void StartServer()
{
IPAddress ipaddr = IPAddress.Parse(GetLocalIPAddress());
int nport = 23000;
mTcpListener = new TcpListener(ipaddr, nport);
mTcpListener.Start();
txtMessages.Text += "Server Listening on IP: " + ipaddr + " Port: " + nport + Environment.NewLine;
mTcpListener.BeginAcceptTcpClient(ServerAcceptClient, mTcpListener);
}
void ServerAcceptClient(IAsyncResult iar)
{
TcpListener tcpl = (TcpListener)iar.AsyncState;
mTcpClient = tcpl.EndAcceptTcpClient(iar);
txtMessages.Invoke((MethodInvoker)delegate
{
txtMessages.Text += "Player accepted..." + Environment.NewLine;
});
mRx = new byte[1460];
mTcpClient.GetStream().BeginRead(mRx, 0, mRx.Length, ServerRead, mTcpClient);
}
void ServerRead(IAsyncResult iar)
{
TcpClient tcpc = (TcpClient)iar.AsyncState;
int nReadBytes = 0;
string strRecv = null;
nReadBytes = tcpc.GetStream().EndRead(iar);
if (nReadBytes == 0)
{
txtMessages.Invoke((MethodInvoker)delegate
{
txtMessages.Text += $"Player disconnected...{Environment.NewLine}";
return;
});
}
strRecv = Encoding.UTF8.GetString(mRx, 0, nReadBytes);
//Game classes and/or methods
txtMessages.Invoke((MethodInvoker)delegate
{
txtMessages.Text += strRecv + Environment.NewLine;
});
mRx = new byte[1024];
mTcpClient.GetStream().BeginRead(mRx, 0, mRx.Length, ServerRead, mTcpClient);
}
I've been through some tutorials, build some examples found on the web, I'm now able to get a simple synchronous multithreaded chat for the console. I tried to export those ideas on to windows forms, maybe in a bit naïvely way:
mTcpListener.BeginAcceptTcpClient(ServerThreaded, mTcpListener);
and:
void ServerThreaded(IAsyncResult iar)
{
mTcpListener = (TcpListener)iar.AsyncState;
int nplayer = 1;
while (nplayer <= 4)
{
Console.WriteLine("Waiting for incoming client connections...");
//mTcpClient = mTcpListener.AcceptTcpClient();
//mTcpClient = mTcpListener.EndAcceptTcpClient(iar);
TcpClient player = mTcpListener.AcceptTcpClient();
Console.WriteLine("Accepted new client connection...");
Thread t = new Thread(() => ServerAcceptClient(iar));
t.Start();
nplayer++;
}
}
Obviously it's not working... last exception I was getting on a regular basis were of the form System.InvalidOperationException: "EndAccept can only be called once for each asynchronous operation".
Am I going with this tottaly on the wrong way? Any advice would be much appreciated.
i Am Using JsSoft.Apple.Apns.Notification . When i do sandbox= true. it works fine but when i change into false Notification is not received. also i No error will be arise. Please Tell Me what i missed or Doing wrong?
Apple .p12 Certificate is Created for Production.
here is the Code. or (https://github.com/Redth/APNS-Sharp).
using System;
using System.Collections.Generic;
using System.Text;
using JdSoft.Apple.Apns.Notifications;
namespace JdSoft.Apple.Apns.Test
{
class Program
{
[STAThread]
static void Main(string[] args)
{
//Variables you may need to edit:
//---------------------------------
//True if you are using sandbox certificate, or false if using production
bool sandbox = false;
//Put your device token in here
string testDeviceToken = "7e6baf66c0a908f65e15b9575dd04c291021b7b77079624223b39cd053d38c26";
//Put your PKCS12 .p12 or .pfx filename here.
// Assumes it is in the same directory as your app
string p12File = #"C:\Users\Nouman\source\repos\AsteriskComunicationApi\AsteriskComunicationApi\p12File\VOIP_iOS_New.p12";
//This is the password that you protected your p12File
// If you did not use a password, set it as null or an empty string
string p12FilePassword = "12345678";
//Number of notifications to send
int count = 3;
//Number of milliseconds to wait in between sending notifications in the loop
// This is just to demonstrate that the APNS connection stays alive between messages
int sleepBetweenNotifications = 3000;
//Actual Code starts below:
//--------------------------------
string p12Filename = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, p12File);
NotificationService service = new NotificationService(sandbox, p12Filename, p12FilePassword, 1);
service.SendRetries = 5; //5 retries before generating notificationfailed event
service.ReconnectDelay = 5000; //5 seconds
service.Error += new NotificationService.OnError(service_Error);
service.NotificationTooLong += new NotificationService.OnNotificationTooLong(service_NotificationTooLong);
service.BadDeviceToken += new NotificationService.OnBadDeviceToken(service_BadDeviceToken);
service.NotificationFailed += new NotificationService.OnNotificationFailed(service_NotificationFailed);
service.NotificationSuccess += new NotificationService.OnNotificationSuccess(service_NotificationSuccess);
service.Connecting += new NotificationService.OnConnecting(service_Connecting);
service.Connected += new NotificationService.OnConnected(service_Connected);
service.Disconnected += new NotificationService.OnDisconnected(service_Disconnected);
//The notifications will be sent like this:
// Testing: 1...
// Testing: 2...
// Testing: 3...
// etc...
for (int i = 1; i <= count; i++)
{
//Create a new notification to send
Notification alertNotification = new Notification(testDeviceToken);
alertNotification.Payload.Alert.Body = string.Format("Testing {0}...", i);
alertNotification.Payload.Sound = "default";
alertNotification.Payload.Badge = i;
//Queue the notification to be sent
if (service.QueueNotification(alertNotification))
Console.WriteLine("Notification Queued!");
else
Console.WriteLine("Notification Failed to be Queued!");
//Sleep in between each message
if (i < count)
{
Console.WriteLine("Sleeping " + sleepBetweenNotifications + " milliseconds before next Notification...");
System.Threading.Thread.Sleep(sleepBetweenNotifications);
}
}
Console.WriteLine("Cleaning Up...");
//First, close the service.
//This ensures any queued notifications get sent befor the connections are closed
service.Close();
//Clean up
service.Dispose();
Console.WriteLine("Done!");
Console.WriteLine("Press enter to exit...");
Console.ReadLine();
}
}
}
I want to consume SAP web service into my c# application. For that i wrote one block of code given below.
NetworkCredential ntobj = new NetworkCredential();
ZWEBSERVICE_INTERNAL_ORDER2 zClassobj = new ZWEBSERVICE_INTERNAL_ORDER2();
ZbapiFiCreateInternalOrder zMethodObj = new ZbapiFiCreateInternalOrder();
ZbapiFiCreateInternalOrderResponse zMethodResobj = new ZbapiFiCreateInternalOrderResponse();
ntobj.UserName = "alpldev";
ntobj.Password = "alpl123";
zClassobj.PreAuthenticate = true;
zClassobj.Credentials = ntobj;
zMethodObj.IDriverNo = "KD00000014";
zMethodObj.IPlant = "1001";
zMethodObj.ITripNo = "1001201406140027";
zMethodObj.IVhclNo = "AP29Q8639";
zMethodResobj = zClassobj.ZbapiFiCreateInternalOrder(zMethodObj);
but at last line i got "underlying connection established was closed. unexpected format was send" error.
please help me...
I'm actually using a soap service for a SAP WebService and I think I know what the problem is. You have to do first a Request including the QaaWsHeader and the ReportBlock configuration, then create the Request and finally with help with the ServicesSoapClient make the method to send your result.
Use this as an example, I hope this will help, good luck
Sellers.QaaWSHeader qaawsHeaderDatos = new Sellers.QaaWSHeader();
Sellers.GetReportBlock_WBS_Sellers getReportBlock = new Sellers.GetReportBlock_WBS_Sellers();
getReportBlock.login = userWS;
getReportBlock.password = passWS;
getReportBlock.refresh = true;
getReportBlock.startRow = 0;
getReportBlock.startRowSpecified = true;
getReportBlock.endRow = 1000;
getReportBlock.endRowSpecified = true;
Sellers.GetReportBlock_WBS_Sellers_Request WSRequest = new Sellers.GetReportBlock_WBS_Sellers_Request(qaawsHeaderDatos, getReportBlock);
Sellers.BIServicesSoap BiService = new Sellers.BIServicesSoapClient();
Sellers.GetReportBlock_WBS_Sellers_Response FinalResponse = BiService.GetReportBlock_WBS_Sellers(WSRequest);
object[][] yourTable = FinalResponse.table;