How to get the assigned port of a GrpcServer - c#

I want to create a gRPC server and bind it to a random port.
The documentation states that port 0 (ServerPort.PickUnused = 0) can be passed to achieve this:
var server = new Server
{
Ports = { new ServerPort("0.0.0.0", ServerPort.PickUnused, ServerCredentials.Insecure) }
};
// ... adding some services
server.Start();
How can I determine which port has been assigned to the server?
The passed ServerPort still mentions 0:
var enumerator = server.Ports.GetEnumerator();
enumerator.MoveNext();
var serverPort = enumerator.Current as ServerPort;
Debug.Log($"RPC Server started on port {serverPort.Port}");
// Out: RPC Server started on port 0

Sometimes reading the WHOLE documentation page BEFORE googling around would save so much time.
ServerPort has a property named BoundPort (quote: "The port actually bound by the server.
This is useful if you let server pick port automatically.")
This returns the actual port:
Debug.Log($"RPC Server started on port {serverPort.BoundPort}");

Related

C# - Detect public ip adress change, VPN issue

With following code I am able to track public IP changes of my desktop application. This should be able to track if either the public IP changed or the user enabled a VPN to change his public IP. This code is run on application launch and used once again when a check is needed:
public class PublicIP
{
IPAddress last_ip=null;
DateTime timestamp_lastipchange;
public void UpdateIP()
{
List<string> hosts = new List<string>()
{
"https://api.ipify.org",
"https://ipinfo.io/ip",
"https://checkip.amazonaws.com",
"https://wtfismyip.com/text",
"http://icanhazip.com"
};
using(WebClient webclient = new WebClient())
{
foreach(string host in hosts)
{
//Download each string from hosts until an IP could be fetched
try{
var newip = IPAddress.Parse(webclient.DownloadString(service)); //Downloading the string
if(!newip.IsEqual(last_ip) && last_ip!=null) timestamp_lastipchange = DateTime.Now; //Check if the ip changed, if the last known ip does not exists skipp this step
last_ip = newip; //Save last known ip
return;
}
catch { }
}
}
}
}
This approach seems to work pretty well, however during UnitTesting some workflows do not fetch a new IP:
IP change by switching networks: change gets successfully detected
IP changed by provider: change gets successfully detected
VPN was enabled when the application was launched and is then turned off:
change gets successfully detected
VPN was disabled on application start and is turned on during runtime:
change does not get detected. Webclient.DownloadString() still returns the same IP as if the VPN was not enabled.
I am not really sure what is happening in workflow nr 4. Do I have to manually select the new network interface (VPN)? Or is this a caching problem on the client/server side?
WebClient is high-level and might using static pool behind-the-scene (and also deprecated). You might try using HttpClient instead, because HttpClient handle connection via its message handler, and the default one is not static, which means this should work:
using(var httpClient = new HttpClient())
{
var newip = IPAddress.Parse(webclient.GetStringAsync(service)
.ConfigureAwait(false).GetAwaiter().GetResult());
// ...
}

c# how to return a string from a client to a server in TCP and UDP

So in my client I am looking for a way to return how many times a background worker was run to a server. Here is the code section for the client:
}
public int searchcount = 1;
public void SL_Click(object sender, EventArgs e)
{
try
{
TcpClient tcpclnt = new TcpClient();
tcpclnt.Connect(RecieveIP.Text, 8001); // use the ipaddress as in the server program
MessageBox.Show("Connected");
Stream stm = tcpclnt.GetStream();
MessageBox.Show("Listening for information......");
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
string atk = Encoding.UTF8.GetString(bb.AsSpan(0, k));
Console.WriteLine($"S Connected to attack server at IPv4 address {RecieveIP.Text} Attack command Received: {atk}. If command is g, attacking google. Y means attacking yahoo. A means attacking aol. Yo meants attacking youtube, and s is attacking spotify");//test
//if you want your check
//this will not work if your incoming data contains white space or other bytes that were converted.
if (atk == "g" || atk.Contains("g"))
MessageBox.Show("Recieved Command " + atk);
if (atk == "g")
{
MessageBox.Show("Google");
search.RunWorkerAsync();
On thought, I do have a string
public int searchcount = 1;
Which the background worker in question adds one to display to the person running the client how many times it was run.
Console.WriteLine("Since start: " + count++.ToString());
Is there a way to return the count++ string to the server via both TCP and UDP? Thanks.
TCP(socket) is a protocol that you can send packages both ways. Udp on the other hand is stateless, you can only send packages from client to server. You cant maintain UDP connections open and keep sending/receiving packages. That said, you can send packages from client to server using UDP if the server dont need to respond your package.
I'm really doing some resume on what tcp/udp protocols are and i really encourage you to read about them on MS official docs before using anything on production.
Here some TCP , UDP and sockets examples and documentation on MS official docs.
Tcp Client/Server
Udp Client/Server
Sockets

How to use tcplistener and tcpclient on device and computer with different ip in same Network?

I'm trying to communicate with a modbus device in my network at ip 192.168.1.76. My host computer address is 192.168.1.132. I'm not able to connect to or listen to device ip.
basically i'm using NModbus4 library. I've created a ModbusTCPSlave and attached the tcp listener to it. then i assigned ModbusSlaveRequestReceived event to that slave. but it gives nothing in return when i try to change register values directly from Modscan software.
Main()
{
var masterEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.132"), 502);
var listener = new TcpListener(IPAddress.Any, 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, new TcpListener(masterEndpoint), 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
}
private static void Modbus_Request_Event(object sender, Modbus.Device.ModbusSlaveRequestEventArgs e)
{
//disassemble packet from master
byte fc = e.Message.FunctionCode;
byte[] data = e.Message.MessageFrame;
byte[] byteStartAddress = new byte[] { data[3], data[2] };
byte[] byteNum = new byte[] { data[5], data[4] };
Int16 StartAddress = BitConverter.ToInt16(byteStartAddress, 0);
Int16 NumOfPoint = BitConverter.ToInt16(byteNum, 0);
Console.WriteLine(fc.ToString() + "," + StartAddress.ToString() + "," + NumOfPoint.ToString());
}
I expect to get function code, start address and number of points in console application when any register value is changed
I copied your code. Changed the IP address to my "server" and it worked.
So, the issue you are having is either in the setup of your "server" or in the PLC program.
I thought that I had to do some port forwarding on my router. I did not. It did not make a difference.
Server setup:
Your "server"'s IP address needs to be static. Whether your 'server' is your development system or not. And don't forget when you deploy... Server's IP address has to be static as well (not that it wouldn't be...just saying)
Add an inbound Firewall rule to allow connections to the port, in this case 502, otherwise you'll have to allow access every time you launch/start a test.
PLC program
I am using Click PLC's by Koyo. Not sure if this is the rule for all PLC's or not; but, we had to add a line of code to "write" the values we wanted to pick up off the TCP stream. Without the write, the PLC was not sending out a request to join the TcpListener.
Last:
The code to start your listener only needs to be this:
var listener = new TcpListener(IPAddress.Parse("192.168.1.244"), 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, listener, 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();

Perform SNMP walk using SharpSnmpLib BulkWalk method

I am trying to retrieve the MAC address of a device that connects to the network. My goal is to perform a WALK and then search the results by the port number that triggered the event.
I first grab the port information via a GetRequestMessage (Success). Then I TRY to perform a walk to get the MAC Address table. I do not get any errors or exceptions, but I also do not get any results.
Where am I going wrong?
// Capture IPAddress
string ipAddress = e.Sender.Address.ToString();
// Capture the port
string port = e.Message.Scope.Pdu.Variables[0].Data.ToString();
// Setup Authentication with password from App.Config
var auth = new SHA1AuthenticationProvider(new OctetString(_Password));
// Setup Privacy with Phrase from App.Config
var priv = new DESPrivacyProvider(new OctetString(_Phrase), auth);
// Setup username from App.Config
OctetString userName = new OctetString(_Username);
// Create IPEndPoint
IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), 161);
// Create discovery
Discovery discovery = Messenger.GetNextDiscovery(SnmpType.GetRequestPdu);
// Create report
ReportMessage report = discovery.GetResponse(60000, iPEndPoint);
// Setup OID variables to get port information
List<Variable> variables = new List<Variable>
{
// Port Description
new Variable(new ObjectIdentifier($"1.3.6.1.2.1.31.1.1.1.18.{ port }")),
// Port PVID
new Variable(new ObjectIdentifier($"1.3.6.1.2.1.17.7.1.4.5.1.1.{ port }")),
// Voice VLAN
new Variable(new ObjectIdentifier($"1.3.6.1.4.1.674.10895.5000.2.6132.1.1.1.2.13.1.28.{ port }")),
};
// Create SNMP request
GetRequestMessage request = new GetRequestMessage(VersionCode.V3, Messenger.NextMessageId, Messenger.NextRequestId, userName, variables, priv, Messenger.MaxMessageSize, report);
// Send request and get reply
ISnmpMessage reply = request.GetResponse(60000, iPEndPoint);
// Request failed
if (reply.Pdu().ErrorStatus.ToInt32() != 0) // != ErrorCode.NoError
{
throw ErrorException.Create(
"error in response",
IPAddress.Parse(ipAddress),
reply);
}
// Store reply information
string Port_Description = reply.Scope.Pdu.Variables[0].Data.ToString(),
Port_Pvid = reply.Scope.Pdu.Variables[1].Data.ToString(),
Port_VLAN = reply.Scope.Pdu.Variables[2].Data.ToString();
// Create BulkWalk Discovery
// TODO: Do I need to do this or can I reuse the original discovery??
Discovery BULKWALK_discovery = Messenger.GetNextDiscovery(SnmpType.GetRequestPdu);
// Create BulkWalk report
// TODO: Do I need to do this or can I reuse the original report??
ReportMessage BULKWALK_report = BULKWALK_discovery.GetResponse(60000, iPEndPoint);
// Variable to store the results of the WALK
var BULKWALK_results = new List<Variable>();
// Perform the walk and return the count of results. Community name from App.Config
var BULKWALK_results_count = Messenger.BulkWalk(VersionCode.V3, iPEndPoint, new OctetString(_CommunityName), OctetString.Empty, new ObjectIdentifier($"1.3.6.1.2.1.17.7.1.2.2.1.2"), BULKWALK_results, 60000, 10, WalkMode.WithinSubtree, priv, BULKWALK_report);
Debugger.Break();
EDIT
Also, I am using this resource as guidance.
So I found the issue, which was two fold.
The first was when instantiating the Discovery for the BulkWalk, it needs to be as follows:
Discovery discovery = Messenger.GetNextDiscovery(SnmpType.GetBulkRequestPdu);
The key part being getting the SnmpType correct (my code above is SnmpType.GetRequestPdu and not SnmpType.GetBulkRequestPdu). The tutorial does not mention that the SnmpType is different.
Second, when passing parameters into the Messenger.BulkWalk() method I was passing in the community name and not the user name. The source code remarks for the BulkWalk method does say community name but it should be the user.
I did as Lex Li suggested and complied/ran the snmpwalk sample to verify that there were no issues. After that was a success, I went back and reviewed the source code for that sample and found the two issues.

Sending data from a TCP Client (C) to a server (C#/WinForms)

I'm working with a WiFi module written in C that connects to a TCP server written in C++/WinAPI. At the moment, I'm trying to write up some documentation on the protocol being used, as none currently exists. In order to make this a bit easier, I've written a simple application in C#/WinForms in order to more easily send and read received packets.
When working with the existing server, the module connects and then sends a packet with a serial number (i.e. #12345) as a byte array. A green LED also begins blinking when connected to the socket.
When using my new testing server, the server detects that the client is connected (socket.Connected == true), then StreamReader.ReadLine() begins receiving endless nulls. The LED on the client also does not blink green, so it looks as though the client is not connected to the socket.
I don't have a ton of experience with TCP/IP, can anyone see any flaws with the route I'm taking or think of any possible reason why the client end isn't detecting the connection/ sending it's serial number, while the server seems to be working just fine? Thanks in advance for any input.
EDIT:
Here is some of the state machine the module uses to connect to the server..
switch(TransmitState)
{
case CHECK_POLLTIME:
if(PollCounter >= Device.MinutesPerPoll)
{
PollCounter = 0;
TransmitState++; // initiate server communications
}
break;
case LOAD_SOCKET:
if(AppConfig.IsLinked != LINKED) break;
// Connect a socket to the remote TCP server
if(!TCPIsConnected(socket))
socket= TCPOpen(server_ip, server_port);
TransmitState++;
Timer = TickGet();
break;
case POLL_SERVER:
// Wait for the remote server to accept our connection request
if(!TCPIsConnected(socket))
{
// Time out if too much time is spent in this state
if(TickGet()-Timer > 5*TICK_SECOND)
{
// Close the socket so it can be used by other modules
TransmitState = SM_DISCONNECT;
}
break;
}
Timer = TickGet();
if(Bootloader)
break;
// Make certain the socket can be written to
if(U2Tx.count != 0) break;
// Place the application protocol data into the transmit buffer.
//packet needs to include UART commands to get through
TCPBuffer[0] = 0x1B; //ESC
TCPBuffer[1] = 'Z';
TCPBuffer[2] = AppConfig.ConnectionID;
TCPBuffer[3] = '0';
TCPBuffer[4] = '0';
TCPBuffer[5] = '0';
TCPBuffer[6] = '6';
TCPBuffer[7] = '#'; // represents serial number
TCPBuffer[8] = Device.Serial[0];
TCPBuffer[9] = Device.Serial[1];
TCPBuffer[10] = Device.Serial[2];
TCPBuffer[11] = Device.Serial[3];
TCPBuffer[12] = Device.Serial[4];
WF_TxBlock(TCPBuffer, 13);
TransmitState++;
break;
case PROCESS_RESPONSE:
...

Categories

Resources