I am trying to communicate with a PLC over modbus via RS232, but it simply keeps saying that my message from should contain at least 6 bytes of data.
First of all I am sorry for the outlining I always seem to struggle with the code input..., I used the same class for a TCP/IP modbus connection which seems to work quite good, now I am trying to do the same via RTU RS232
I added both of my classes in the edit, thanks in advance I hope someone can help me out.
namespace ConsoleApplication2
{
class Program
{
public static ModBusDriver modbusDriver;
static void Main(string[] args)
{
SerialPort port = new SerialPort("COM1");
port.BaudRate = 38400;
port.DataBits = 8;
port.ReadTimeout = 600;
port.WriteTimeout = 600;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
modbusDriver = new ModBusDriver(port);
modbusDriver.connect(1);
byte slaveAddress = 1;
modbusDriver.WriteMultipleCoils(slaveAddress, 8193, new bool[6] { false, false, false, false, false, false });
Console.WriteLine("done");
Console.Read();
}
Modbusdriver.cs
using Modbus.Device;
using System;
using System.IO.Ports;
using System.Net.Sockets;
using System.Threading;
namespace CoCoSModBusDriver
{
// based on nmodbus4:
// -https://github.com/NModbus4/NModbus4
class ModBusDriver
{
public int connected;
private bool gotClient = false;
public IModbusSerialMaster modbusConnector;
public SerialPort serialPort;
public ModBusDriver(SerialPort port)
{
serialPort = port;
modbusConnector = ModbusSerialMaster.CreateRtu(port);
}
public void connect(int retries)
{
int retryCounter = 0;
while (retryCounter < retries || retries == -1)
{
try
{
serialPort.Open();
}
catch (Exception ex)
{
retryCounter++;
Thread.Sleep(5000);
}
}
}
public void WriteMultipleCoils(byte slaveAdress, ushort startAdress, bool[] data)
{
try
{
modbusConnector.WriteMultipleCoils(slaveAdress, startAdress, data);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
You are missing the slave address in the request. From the IModbus master interface:
/// <summary>
/// Writes a sequence of coils.
/// </summary>
/// <param name="slaveAddress">Address of the device to write to.</param>
/// <param name="startAddress">Address to begin writing values.</param>
/// <param name="data">Values to write.</param>
void WriteMultipleCoils(byte slaveAddress, ushort startAddress, bool[] data);
You should use ModbusSerialMaster class. There is a good example at mesta automations homepage.
Related
I´m doing multiplayer and my Unity console writes this error "Cannot access a disposed object.
Object name: 'System.Net.Sockets.UdpClient'." when I close the server. I don't know what to do with it... Can anyone please advise me how to fix this?
This is my Server.cs file:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
public class Server
{
public static int MaxPlayers { get; private set; }
public static int Port { get; private set; }
public static Dictionary<int, Client> clients = new Dictionary<int, Client>();
public delegate void PacketHandler(int _fromClient, Packet _packet);
public static Dictionary<int, PacketHandler> packetHandlers;
private static TcpListener tcpListener;
private static UdpClient udpListener;
/// <summary>Starts the server.</summary>
/// <param name="_maxPlayers">The maximum players that can be connected simultaneously.</param>
/// <param name="_port">The port to start the server on.</param>
public static void Start(int _maxPlayers, int _port)
{
MaxPlayers = _maxPlayers;
Port = _port;
Debug.Log("Starting server...");
InitializeServerData();
tcpListener = new TcpListener(IPAddress.Any, Port);
tcpListener.Start();
tcpListener.BeginAcceptTcpClient(TCPConnectCallback, null);
udpListener = new UdpClient(Port);
udpListener.BeginReceive(UDPReceiveCallback, null);
Debug.Log($"Server started on port {Port}.");
}
/// <summary>Handles new TCP connections.</summary>
private static void TCPConnectCallback(IAsyncResult _result)
{
TcpClient _client = tcpListener.EndAcceptTcpClient(_result);
tcpListener.BeginAcceptTcpClient(TCPConnectCallback, null);
Debug.Log($"Incoming connection from {_client.Client.RemoteEndPoint}...");
for (int i = 1; i <= MaxPlayers; i++)
{
if (clients[i].tcp.socket == null)
{
clients[i].tcp.Connect(_client);
return;
}
}
Debug.Log($"{_client.Client.RemoteEndPoint} failed to connect: Server full!");
}
/// <summary>Receives incoming UDP data.</summary>
private static void UDPReceiveCallback(IAsyncResult _result)
{
try
{
IPEndPoint _clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] _data = udpListener.EndReceive(_result, ref _clientEndPoint);
udpListener.BeginReceive(UDPReceiveCallback, null);
if (_data.Length < 4)
{
return;
}
using (Packet _packet = new Packet(_data))
{
int _clientId = _packet.ReadInt();
if (_clientId == 0)
{
return;
}
if (clients[_clientId].udp.endPoint == null)
{
// If this is a new connection
clients[_clientId].udp.Connect(_clientEndPoint);
return;
}
if (clients[_clientId].udp.endPoint.ToString() == _clientEndPoint.ToString())
{
// Ensures that the client is not being impersonated by another by sending a false clientID
clients[_clientId].udp.HandleData(_packet);
}
}
}
catch (Exception _ex)
{
Debug.Log($"Error receiving UDP data: {_ex}");
}
}
/// <summary>Sends a packet to the specified endpoint via UDP.</summary>
/// <param name="_clientEndPoint">The endpoint to send the packet to.</param>
/// <param name="_packet">The packet to send.</param>
public static void SendUDPData(IPEndPoint _clientEndPoint, Packet _packet)
{
try
{
if (_clientEndPoint != null)
{
udpListener.BeginSend(_packet.ToArray(), _packet.Length(), _clientEndPoint, null, null);
}
}
catch (Exception _ex)
{
Debug.Log($"Error sending data to {_clientEndPoint} via UDP: {_ex}");
}
}
/// <summary>Initializes all necessary server data.</summary>
private static void InitializeServerData()
{
for (int i = 1; i <= MaxPlayers; i++)
{
clients.Add(i, new Client(i));
}
packetHandlers = new Dictionary<int, PacketHandler>()
{
{ (int)ClientPackets.welcomeReceived, ServerHandle.WelcomeReceived },
{ (int)ClientPackets.playerMovement, ServerHandle.PlayerMovement },
{ (int)ClientPackets.playerShoot, ServerHandle.PlayerShoot },
{ (int)ClientPackets.playerThrowItem, ServerHandle.PlayerThrowItem }
};
Debug.Log("Initialized packets.");
}
public static void Stop()
{
tcpListener.Stop();
udpListener.Close();
}
}
A tutorial according to which I make a multiplayer game:
https://www.youtube.com/playlist?list=PLXkn83W0QkfnqsK8I0RAz5AbUxfg3bOQ5
It's because the garbage collector has disposed the udpClient and you are trying to call the Stop() method in a disposed object.
So , try replacing this method instead of your Stop method
public static void Stop()
{
try
{
tcpListener.Stop();
udpListener.Close();
}
catch {}
}
I have created a class that acts as a plugin for another application. It should hold functions to use in the main application. It works in general - that means i can handle usual functions like calculations and even reading files. But i have problems implementing a socket class. I know how to work with sockets in general but in this case i have a problem.
As you may see in the code, there is an internal class SockAttrib that should manage the socket creation, the listening and also the messages. Received messages are stored in a dictionary.
public class Net : Module {
private static ReadOnlyCollection<CustomMethod> customMethods;
internal class SockAttrib {
public Socket listener;
public Socket handler;
/* create the listener */
public SockAttrib(int port) {
IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[1];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
try {
listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(10);
handler = listener.Accept();
} catch (Exception e) { Console.WriteLine("socket() " + e); }
}
/* listen */
public SockAttrib() {
try {
// Incoming data from the client.
string data = "";
byte[] bytes = null;
while (true) {
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>") > -1)
{
messages[++idm] = data;
//return;
}
}
}
catch (Exception e) { Console.WriteLine("listen() "+e); }
}
public void Close() {
handler.Close();
}
}
/* message index */
private static int idm = 0;
/* list of messages */
private static Dictionary<int, String> messages = new Dictionary<int, String>();
public Net() {
if (customMethods != null) return;
List<CustomMethod> moduleMethods = new List<CustomMethod>();
moduleMethods.Add(new CustomMethod(typeof(int), "socket", typeof(int)));
moduleMethods.Add(new CustomMethod(typeof(int), "listen" ));
moduleMethods.Add(new CustomMethod(typeof(string), "sockread"));
customMethods = moduleMethods.AsReadOnly();
}
public ReadOnlyCollection<CustomMethod> Prototypes {
get { return customMethods; }
}
public object OnMethodInvoke(String functionName, List<object> parameters) {
if( functionName == "socket") {
int port = (int)parameters[0];
SockAttrib sa = new SockAttrib( port );
return 1;
}
if (functionName == "listen") {
SockAttrib sa = new SockAttrib();
return 1;
}
if (functionName == "sockread") {
if (idm > 0) {
String message = messages[--idm];
return message;
} else {
return "nope";
}
}
return false;
}
}
My problem is the handler. The creation of the socket works but as soon as i connect to the socket using netcat the socket stop listening and i dont get any responses. I hope its not too much code and it should also be easy readable.
Finally the module gets exported as a library (dll) so i cant really give a minimal working example without also posting the module handler.
Though your requirements are still a bit fuzzy, I will give it a try.
First I would recommend to create a class containing the core functionality of your TCP server. This makes it easier to unit-test your code and to adapt it to changing requirements.
/// <summary>
/// This class encapsulates the TCP server
/// </summary>
public class Server : IDisposable
{
private static TcpListener _listener;
private static TcpClient _client;
private static NetworkStream _stream;
private static byte[] _buffer;
private static readonly StringBuilder _receivedText = new StringBuilder();
private const string EOF = "<EOF>";
/// <summary>
/// Starts listening on the specified port
/// </summary>
/// <param name="port">The port number</param>
public Server(int port)
{
_listener = new TcpListener(IPAddress.Any, port);
_listener.Start();
_listener.BeginAcceptTcpClient(Accepted, null);
}
public void Dispose()
{
if (_client != null)
{
_client.Dispose();
}
if (_listener != null)
{
_listener.Stop();
}
}
/// <summary>
/// Returns any text that has been sent via TCP to the port specified in the constructor.
/// </summary>
/// <returns>The received text, or null if no (complete) text has been received yet.</returns>
/// <remarks>
/// The method returns the next text delimited by "<EOF>".
/// </remarks>
public string Read()
{
lock (_receivedText)
{
var receivedText = _receivedText.ToString();
var eofIndex = receivedText.IndexOf(EOF);
if (eofIndex < 0)
return null; // no (complete) text has been received yet
var result = receivedText.Substring(0, eofIndex);
_receivedText.Remove(0, eofIndex + EOF.Length);
return result;
}
}
// called whenever a client has connected to our server.
private static void Accepted(IAsyncResult ar)
{
_client = _listener.EndAcceptTcpClient(ar);
_stream = _client.GetStream();
_buffer = new byte[4096];
_stream.BeginRead(_buffer, 0, _buffer.Length, Read, null);
}
// called whenever data has arrived or if the client closed the TCP connection
private static void Read(IAsyncResult ar)
{
var bytesReceived = _stream.EndRead(ar);
if (bytesReceived == 0)
{
// TCP connection closed
_client.Close();
_client = null;
_stream.Dispose();
_stream = null;
// prepare for accepting the next TCP connection
_listener.BeginAcceptTcpClient(Accepted, null);
return;
}
lock (_receivedText)
{
_receivedText.Append(Encoding.ASCII.GetString(_buffer, 0, bytesReceived));
}
// prepare for reading more
_stream.BeginRead(_buffer, 0, _buffer.Length, Read, null);
}
}
Integrating this into your Net class should then be fairly simple:
// static or not? Depends on your "Module plugin" architecture
private static Server _server;
public object OnMethodInvoke(String functionName, List<object> parameters)
{
if (functionName == "socket")
{
if (_server != null)
{
// oops, already open
return 0;
}
int port = (int)parameters[0];
_server = new Server(port);
return 1;
}
if (functionName == "sockread")
{
if (_server != null)
{
return _server.Read() ?? "nope";
}
else
{
return "nope";
}
}
return false;
}
I'm trying to make it so that whenever a TCP client receives data, it triggers a function call. The function I'm trying to call just performs a function call on another class. But however I try it, it keeps giving me the same error: Cannot assign "OnDataReceived" because it's a 'method group'
Code from my form1:
namespace Liberly
{
public partial class Form1 : Form
{
TcpClient tcpClient;
public Form1()
{
InitializeComponent();
tcpClient = new TcpClient();
tcpClient.OnDataReceived += data;
}
private void data(string text)
{
}
private void button1_Click(object sender, EventArgs e)
{
tcpClient.Connect("127.0.0.1", 2222);
}
private void button2_Click(object sender, EventArgs e)
{
tcpClient.Disconnect();
}
}}
Code from my TCP client library:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Liberly
{
class TcpClient
{
private Socket sender;
private IPEndPoint remoteEP;
private IPAddress ipAddress;
private IPHostEntry ipHostInfo;
private bool run;
private int bytesRec;
private string data;
private byte[] bytes = new byte[1024];
Thread clientT;
/// <summary>
/// Connect with desired ip adress and port
/// </summary>
/// <param name="ip">Ip address</param>
/// <param name="port">Port</param>
public void Connect(string ip,int port)
{
//Setup ip and port
ipHostInfo = Dns.Resolve(ip);
ipAddress = ipHostInfo.AddressList[0];
remoteEP = new IPEndPoint(ipAddress, port);
//Start client thread
clientT = new Thread(new ThreadStart(client));
run = true;
clientT.Start();
}
/// <summary>
/// Disconnect from a server
/// </summary>
public void Disconnect()
{
if (run)
{
try
{
run = false;
if (sender.Connected)
{
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
clientT.Interrupt();
}
catch { }
}
else
{
Debug.WriteLine("TCP CLIENT/Client is not connected");
}
}
/// <summary>
/// Send data to the server
/// </summary>
/// <param name="text">Text</param>
public void Send(string text)
{
if (sender.Connected)
sender.Send(Encoding.ASCII.GetBytes(text));
else
Debug.WriteLine("TCP CLIENT/Unable to send, not connected");
}
/// <summary>
/// Returns bool if client is connected to the server
/// </summary>
/// <returns></returns>
public bool Connected { get { return sender.Connected; } }
//Function that runs when data is received
public string OnDataReceived()
{
return data;
}
//Client void
private void client()
{
try {
//Create socket and connect
sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Connect(remoteEP);
Debug.WriteLine("TCP CLIENT/Connected");
//Loop for receiving data
while (run)
{
bytesRec = sender.Receive(bytes);
data = Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data != null)
{
Debug.WriteLine("TCP CLIENT/Received data:" + data);
if (data == "")
{
Debug.WriteLine("TCP CLIENT/Disconnected");
break;
}
else
{
//Here is the data that is received//
OnDataReceived();
}
}
data = null;
}
}
catch (ArgumentNullException ane)
{
Console.WriteLine("TCP CLIENT/ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("TCP CLIENT/SocketException : {0}", se.ToString());
} catch (Exception e)
{
Console.WriteLine("TCP CLIENT/Unexpected exception : {0}", e.ToString());
}
}
}}
You can use events:
public delegate void onDataReceivedEvent(string message);
public event onDataReceivedEvent onDataReceived;
public void sendNewData(string message){
if(!onDataReceived!=null){
onDataReceived.Invoke(message);
}
}
Then register your event:
onDataReceived+= someMethod;
private void someMethod(string message){
//process message;
}
You have a function
//Function that runs when data is received
public string OnDataReceived()
{
return data;
}
in your TCPClient class. You need to change its name.
Or add a event / delegate combo in this library class.
To keep the intro short, I will mention that I have been building an application that involves executing remote commands from a private website that I have built and having my personal home computer respond to those commands.
I discovered that live desktop-streaming would be a perfect feature, and I am planning to use an iframe to fit it into my site. However, I cannot seem to find a good C# library which will allow me to stream my desktop in realtime.
Other than this one: http://www.codeproject.com/Articles/371955/Motion-JPEG-Streaming-Server
The problem is, that only allows me to stream my desktop to localhost, 127.0.0.1, and the other local host links.
I need a way to modify it to be able to have it stream to a server of my choice, from which I can then access it. For example www.mystream.com/stream.php
It consists of two classes: ImageStreamingServer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using System.IO;
// -------------------------------------------------
// Developed By : Ragheed Al-Tayeb
// e-Mail : ragheedemail#gmail.com
// Date : April 2012
// -------------------------------------------------
namespace rtaNetworking.Streaming
{
/// <summary>
/// Provides a streaming server that can be used to stream any images source
/// to any client.
/// </summary>
public class ImageStreamingServer:IDisposable
{
private List<Socket> _Clients;
private Thread _Thread;
public ImageStreamingServer():this(Screen.Snapshots(600,450,true))
{
}
public ImageStreamingServer(IEnumerable<Image> imagesSource)
{
_Clients = new List<Socket>();
_Thread = null;
this.ImagesSource = imagesSource;
this.Interval = 50;
}
/// <summary>
/// Gets or sets the source of images that will be streamed to the
/// any connected client.
/// </summary>
public IEnumerable<Image> ImagesSource { get; set; }
/// <summary>
/// Gets or sets the interval in milliseconds (or the delay time) between
/// the each image and the other of the stream (the default is .
/// </summary>
public int Interval { get; set; }
/// <summary>
/// Gets a collection of client sockets.
/// </summary>
public IEnumerable<Socket> Clients { get { return _Clients; } }
/// <summary>
/// Returns the status of the server. True means the server is currently
/// running and ready to serve any client requests.
/// </summary>
public bool IsRunning { get { return (_Thread != null && _Thread.IsAlive); } }
/// <summary>
/// Starts the server to accepts any new connections on the specified port.
/// </summary>
/// <param name="port"></param>
public void Start(int port)
{
lock (this)
{
_Thread = new Thread(new ParameterizedThreadStart(ServerThread));
_Thread.IsBackground = true;
_Thread.Start(port);
}
}
/// <summary>
/// Starts the server to accepts any new connections on the default port (8080).
/// </summary>
public void Start()
{
this.Start(8080);
}
public void Stop()
{
if (this.IsRunning)
{
try
{
_Thread.Join();
_Thread.Abort();
}
finally
{
lock (_Clients)
{
foreach (var s in _Clients)
{
try
{
s.Close();
}
catch { }
}
_Clients.Clear();
}
_Thread = null;
}
}
}
/// <summary>
/// This the main thread of the server that serves all the new
/// connections from clients.
/// </summary>
/// <param name="state"></param>
private void ServerThread(object state)
{
try
{
Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Server.Bind(new IPEndPoint(IPAddress.Any,(int)state));
Server.Listen(10);
System.Diagnostics.Debug.WriteLine(string.Format("Server started on port {0}.", state));
foreach (Socket client in Server.IncommingConnectoins())
ThreadPool.QueueUserWorkItem(new WaitCallback(ClientThread), client);
}
catch { }
this.Stop();
}
/// <summary>
/// Each client connection will be served by this thread.
/// </summary>
/// <param name="client"></param>
private void ClientThread(object client)
{
Socket socket = (Socket)client;
System.Diagnostics.Debug.WriteLine(string.Format("New client from {0}",socket.RemoteEndPoint.ToString()));
lock (_Clients)
_Clients.Add(socket);
try
{
using (MjpegWriter wr = new MjpegWriter(new NetworkStream(socket, true)))
{
// Writes the response header to the client.
wr.WriteHeader();
// Streams the images from the source to the client.
foreach (var imgStream in Screen.Streams(this.ImagesSource))
{
if (this.Interval > 0)
Thread.Sleep(this.Interval);
wr.Write(imgStream);
}
}
}
catch { }
finally
{
lock (_Clients)
_Clients.Remove(socket);
}
}
#region IDisposable Members
public void Dispose()
{
this.Stop();
}
#endregion
}
static class SocketExtensions
{
public static IEnumerable<Socket> IncommingConnectoins(this Socket server)
{
while(true)
yield return server.Accept();
}
}
static class Screen
{
public static IEnumerable<Image> Snapshots()
{
return Screen.Snapshots(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height,true);
}
/// <summary>
/// Returns a
/// </summary>
/// <param name="delayTime"></param>
/// <returns></returns>
public static IEnumerable<Image> Snapshots(int width,int height,bool showCursor)
{
Size size = new Size(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height);
Bitmap srcImage = new Bitmap(size.Width, size.Height);
Graphics srcGraphics = Graphics.FromImage(srcImage);
bool scaled = (width != size.Width || height != size.Height);
Bitmap dstImage = srcImage;
Graphics dstGraphics = srcGraphics;
if(scaled)
{
dstImage = new Bitmap(width, height);
dstGraphics = Graphics.FromImage(dstImage);
}
Rectangle src = new Rectangle(0, 0, size.Width, size.Height);
Rectangle dst = new Rectangle(0, 0, width, height);
Size curSize = new Size(32, 32);
while (true)
{
srcGraphics.CopyFromScreen(0, 0, 0, 0, size);
if (showCursor)
Cursors.Default.Draw(srcGraphics,new Rectangle(Cursor.Position,curSize));
if (scaled)
dstGraphics.DrawImage(srcImage, dst, src, GraphicsUnit.Pixel);
yield return dstImage;
}
srcGraphics.Dispose();
dstGraphics.Dispose();
srcImage.Dispose();
dstImage.Dispose();
yield break;
}
internal static IEnumerable<MemoryStream> Streams(this IEnumerable<Image> source)
{
MemoryStream ms = new MemoryStream();
foreach (var img in source)
{
ms.SetLength(0);
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
yield return ms;
}
ms.Close();
ms = null;
yield break;
}
}
}
MjpegWriter
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
// -------------------------------------------------
// Developed By : Ragheed Al-Tayeb
// e-Mail : ragheedemail#gmail.com
// Date : April 2012
// -------------------------------------------------
namespace rtaNetworking.Streaming
{
/// <summary>
/// Provides a stream writer that can be used to write images as MJPEG
/// or (Motion JPEG) to any stream.
/// </summary>
public class MjpegWriter:IDisposable
{
private static byte[] CRLF = new byte[] { 13, 10 };
private static byte[] EmptyLine = new byte[] { 13, 10, 13, 10};
private string _Boundary;
public MjpegWriter(Stream stream)
: this(stream, "--boundary")
{
}
public MjpegWriter(Stream stream,string boundary)
{
this.Stream = stream;
this.Boundary = boundary;
}
public string Boundary { get; private set; }
public Stream Stream { get; private set; }
public void WriteHeader()
{
Write(
"HTTP/1.1 200 OK\r\n" +
"Content-Type: multipart/x-mixed-replace; boundary=" +
this.Boundary +
"\r\n"
);
this.Stream.Flush();
}
public void Write(Image image)
{
MemoryStream ms = BytesOf(image);
this.Write(ms);
}
public void Write(MemoryStream imageStream)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine(this.Boundary);
sb.AppendLine("Content-Type: image/jpeg");
sb.AppendLine("Content-Length: " + imageStream.Length.ToString());
sb.AppendLine();
Write(sb.ToString());
imageStream.WriteTo(this.Stream);
Write("\r\n");
this.Stream.Flush();
}
private void Write(byte[] data)
{
this.Stream.Write(data, 0, data.Length);
}
private void Write(string text)
{
byte[] data = BytesOf(text);
this.Stream.Write(data, 0, data.Length);
}
private static byte[] BytesOf(string text)
{
return Encoding.ASCII.GetBytes(text);
}
private static MemoryStream BytesOf(Image image)
{
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms;
}
public string ReadRequest(int length)
{
byte[] data = new byte[length];
int count = this.Stream.Read(data,0,data.Length);
if (count != 0)
return Encoding.ASCII.GetString(data, 0, count);
return null;
}
#region IDisposable Members
public void Dispose()
{
try
{
if (this.Stream != null)
this.Stream.Dispose();
}
finally
{
this.Stream = null;
}
}
#endregion
}
}
This application should work over internet as well. Make sure that the port you access through it remotely is open.
If you don't want to have to open a port for the app to work. then consider changing the source above to make a reverse connection instead , where your desktop computer acts as a client rather than a server.
Good luck
I have a really weird problem. I tried everything to fix it and so far nothing works.
As you can see in the first image image, when I try to reference the static class "SharedConstants" from a namespace outside "UnnamedGameServer" the compiler returns the following error:
The type or namespace name 'ServerInfo' does not exist in the
namespace 'SharedConstants'
I found a turnaround to this problem referencing this class using UnnamedGameServer.SharedConstants instead of SharedConstants and using UnnamedGameServer; on the top of the .cs file. But I prefer avoiding referencing it on every line I use that class.
Here are some screenshots of my code:
First screenshot:
Second screenshot:
Edit: Screenshot of using statement:
Edit 2: Code without screenshots:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using ProtoBuf;
using UnnamedGameServer;
using System.Threading;
namespace Unnamed_game
{
class Connection
{
public struct UserInformation
{
public string Username;
public int UserID;
}
static private Connection instance;
private Connection()
{
client = new TcpClient();
header = new PacketHeader();
_isLoggedCharacter = false;
_isLoggedUser = false;
magicByte = UnnamedGameServer.SharedConstants.ServerInfo.MagicByte;
}
// properties
TcpClient client;
PacketHeader header;
Thread serverCommThread;
byte[] magicByte;
bool _isLoggedCharacter;
CharacterInformation chInformation
{
get
{
return Player.Instance().Information;
}
}
bool _isLoggedUser;
public UserInformation Information;
// methods
static public Connection Instance()
{
if(instance == null)
{
instance = new Connection();
return instance;
}
else
{
return instance;
}
}
/// <summary>
/// Should never be used. Use the parameterless one to get the server address and information. It doesn't use try-catch, the exception handling should be done on Game1.Initialize()
/// </summary>
public void ConnectServer(IPEndPoint endPoint)
{
if (client.Connected)
{
return;
}
else
{
client.Connect(endPoint);
serverCommThread = new Thread(HandleServerCommunication);
serverCommThread.Start();
}
}
public void ConnectServer()
{
this.ConnectServer(new IPEndPoint(UnnamedGameServer.SharedConstants.ServerInfo.ServerAddress, UnnamedGameServer.SharedConstants.ServerInfo.Port));
}
private void HandleServerCommunication()
{
if (client == null)
{
throw new Exception("The TcpClient is null");
}
else
{
// this doesn't work
byte[] magicByte = SharedConstants.ServerInfo.MagicByte;
// this works
magicByte = UnnamedGameServer.SharedConstants.ServerInfo.MagicByte;
}
}
private void SendPacket(ActionType actionType, object packetStruct)
{
try
{
header.ActionTypeNumber = (short)actionType;
using (NetworkStream stream = client.GetStream())
{
stream.Write(magicByte, 0, magicByte.Length);
Serializer.SerializeWithLengthPrefix<PacketHeader>(stream, header, PrefixStyle.Base128);
switch (actionType)
{
case ActionType.Connect:
Serializer.SerializeWithLengthPrefix<PacketConnect>(stream, (PacketConnect)packetStruct, PrefixStyle.Base128);
break;
}
stream.Write(magicByte, 0, magicByte.Length);
}
}
catch (Exception)
{
// error
return;
}
}
public void CreateNewCharacter(string characterName, CharacterClass chClass, CharacterRace chRace)
{
var info = new NewCharacterInfo();
info.Name = characterName;
info.OwnerUsername = Information.Username;
info.Class = chClass;
info.Race = chRace;
CreateNewCharacter(info);
}
public void CreateNewCharacter(NewCharacterInfo info)
{
var packet = new PacketCreateNewCharacter();
packet.chInfo = info;
SendPacket(ActionType.CreateNewCharacter, packet);
}
public void ConnectUser(string username, string unhashedPassword)
{
var packet = new PacketConnect();
packet.Username = username;
packet.UnhashedPassword = unhashedPassword;
ConnectUser(packet);
}
public void ConnectUser(PacketConnect packet)
{
if (_isLoggedCharacter || _isLoggedUser)
{
return;
}
else
{
SendPacket(ActionType.Connect, packet);
}
}
public void ConnectCharacter(string characterName, short serverID)
{
var packet = new PacketLoginCharacter();
packet.CharacterName = characterName;
packet.ServerID = serverID;
ConnectCharacter(packet);
}
public void ConnectCharacter(PacketLoginCharacter packet)
{
if (_isLoggedCharacter || !_isLoggedUser)
{
return;
}
else
{
SendPacket(ActionType.LoginCharacter, packet);
}
}
public void Disconnect(PacketDisconnect packet)
{
if (!_isLoggedUser)
{
return;
}
else
{
SendPacket(ActionType.Disconnect, packet);
}
}
}
}
edit 3:: Code where SharedConstants is stored.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace UnnamedGameServer
{
/// <summary>
/// ALL CONSTANTS THAT ARE SHARED BY THE CLIENT AND THE SERVER ARE STORED HERE. DONT ADD MORE CLASSES THAT STORE CONSTANTS. Use GameConstants for game-only constants.
/// </summary>
public static class SharedConstants
{
/// <summary>
/// Server information with port, IP and MagicByte
/// </summary>
public static class ServerInfo
{
public const short Port = 6483;
public static readonly IPAddress ServerAddress = IPAddress.Loopback;
public static byte[] MagicByte
{
get
{
return new byte[4] { 0xF1, 0x64, 0x83, 0xC4 };
}
}
}
/// <summary>
/// Character constants shared by client/server
/// </summary>
public static class CharacterConstants
{
public static class Movement
{
/// <summary>
/// Coordinates per update
/// </summary>
public const float DefaultCoordinatePerUpdate = 8;
public const float ModifierNormal = 1f;
public const float ModifierFrozen = 0.8f;
public const float ModifierSpeedBuff = 1.2f;
public const float ModifierStop = 0f;
}
}
/// <summary>
/// Networking constants
/// </summary>
public static class Networking
{
public const int MilisecondsPerMovementUpdate = 100;
public const ushort ActionTypeNonMetaActionStart = 0x0FFF + 1;
/// <summary>
/// What is the number of actions a non-logged user can perform
/// </summary>
public const ushort ActionTypeNonLoggedUser = 0x000F;
}
}
enum CharacterDirection
{
NoMovement = 0x00,
Top = 0x01,
TopRight = 0x02,
TopLeft = 0x03,
Right = 0x04,
BottomRight = 0x05,
Bottom = 0x06,
BottomLeft = 0x07,
Left = 0x08
}
enum CharacterStatus
{
Alive = 0x01,
Dead = 0x02
}
enum CharacterClass
{
Mage = 0x01,
Knight = 0x02
}
enum CharacterRace
{
Human = 0x01
}
enum CharacterType
{
Player = 0x01,
GameMaster = 0x02
}
enum CharacterFaction
{
Newbie = 0x01,
Army = 0x02,
Chaos = 0x03
}
enum CharacterMovementStatus
{
Normal = 0x01,
Frozen = 0x02,
SpeedBuff = 0x03,
Stop = 0x04
}
struct CharacterExperience
{
public CharacterExperience(short level, int experience)
{
Level = level;
Experience = experience;
}
public short Level;
public int Experience;
}
}
Having a using statement should work. If there is any code before the using statements then this may cause a problem.
you could try putting the using statement after the namespace e.g:
namespace Unnamed_game
{
using UnamedGameServer;
class Connection
This should work:
using UnnamedGameServer;
class MyClass {
byte[] b = SharedConstants.ServerInfo.MagicByte;
}
If this doesn't solve your problem, please post the code (in text, not a screenshot) of a short but complete example showing the problem.