التواصل بين عميل C ++ وخادم C # عبر دفق الشبكة

0

لدي برنامج shell صغير حيث يتم كتابة العميل بلغة C ++ والخادم في c #. يجب على العميل كتابة الخادم بعض أوامر أوامر cmd فقط. كل شيء يعمل بشكل مثالي باستثناء شيء واحد: الخادم ينتج مخلفات كاملة !!

هذا هو الخادم في ج #:

    static NetworkStream Stream;
    static byte[] AWNSER = new byte[255];

    static void Main(string[] args)
    {
        TcpListener listen = new TcpListener(IPAddress.Any, 123);
        listen.Start();
        Stream = listen.AcceptTcpClient().GetStream();

        Stream.BeginRead(AWNSER, 0, 255, HNDLR, null);
        while (true)
        {
            var str = Console.ReadLine();
            byte[] MESSAGE = Encoding.UTF8.GetBytes(str + "&& cd");
            Stream.Write(MESSAGE, 0, MESSAGE.Length);
        }
    }
    static void HNDLR(IAsyncResult a)
    {
        Stream.EndRead(a);
        Stream.BeginRead(AWNSER, 0, 255, HNDLR, null);

        Console.WriteLine(Encoding.UTF8.GetString(AWNSER));
    }

هذا هو رمز العملاء في c ++

FILE *fp;
char AWNSER[255];
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);

if (WSAStartup(DllVersion, &wsaData) != 0) //no error
{
    cout << "Winsock startup failed";
}
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
addr.sin_port = htons(123);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("199.166.177.22");
SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL);
if (connect(Connection, (SOCKADDR*)&addr, addrlen) != 0)
{   /*ERROR*/
}
else
{
        fp = _popen("dir", "r");
        while (fgets(AWNSER, 255, fp) != NULL) {
            cout << AWNSER;
            send(Connection, AWNSER, 255, NULL);
            AWNSER[255];
        }
        _pclose(fp);
}

هنا مثال على ما هو إخراج الخادم:

 Volumeseriennummer: BAF0-6BB2
Windows


    ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

 olumeseriennummer: ABF1-7AA3
 Windows
 ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

 olumeseriennummer: ABF1-7AA3
 Windows
 ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
 Verzeichnis von C:\Users\User\Source\MyProblem
 ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

 erzeichnis von C:\Users\User\Source\MyProblem
 ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
30.07.2018  19:08    <DIR>          .
 myProblem

دبرك كثيرا لمساعدتكم

1 إجابة

1
افضل جواب

يرسل عميلك كامل AWNSER مصفوفة حتى لو لم يتم ملؤها بالكامل. يجب أن ترسل فقط ما تم إدخاله بالفعل.

يقوم الخادم بإخراج كل ما يتلقاه ، ولكن بغض النظر عن عدد البايتات التي يتلقاها بالفعل. عليك أن تأخذ في الاعتبار عدد البايتات المستلمة.

TCP هو نقل دفق. لا توجد علاقة 1 إلى 1 بين المرسلين والقراءات. لذلك تحتاج إلى تخزين البيانات الواردة مؤقتًا ، وتنظيم بياناتك بطريقة يمكن للعميل الإشارة إليها عند الانتهاء من إرسال رسالة ، ويمكن للخادم أن يعرف أين تنتهي رسالة كاملة وتبدأ الرسالة التالية. يكفي حرف نهاية أو فاصل أسطر فارغ في المثال البسيط.

لا تعرض سلاسل جزئية. انتظر وصول سلسلة كاملة قبل عرضها. وإلا فإنك تخاطر بإفساد البيانات عند فك تشفير شيء غير جاهز لفك تشفيره بعد.

في معالج الخادم الخاص بك ، لا تتصل Stream.BeginRead() قبل الاتصال Console.WriteLine() . اتصل به بعد الانتهاء من استخدام AWNSER . وإلا فإنك تخاطر AWNSER الكتابة فوقه قبل أن تتاح لك فرصة استخدامه.

جرب شيئًا مثل هذا:

الخادم:

static NetworkStream Stream;
static MemoryStream Data;
static byte[] AWNSER = new byte[256];

static void Main(string[] args)
{
    TcpListener listen = new TcpListener(IPAddress.Any, 123);
    listen.Start();
    Stream = listen.AcceptTcpClient().GetStream();
    Data = new MemoryStream();
    Stream.BeginRead(AWNSER, 0, AWNSER.Length, HNDLR, null);
    while (true)
    {
        var str = Console.ReadLine();
        byte[] MESSAGE = Encoding.UTF8.GetBytes(str + "&& cd\n");
        Stream.Write(MESSAGE, 0, MESSAGE.Length);
    }
}

static void HNDLR(IAsyncResult a)
{
    int numRead = Stream.EndRead(a);
    if (numRead == 0) return;

    Data.Seek(0, SeekOrigin.End);
    Data.Write(AWNSER, 0, numRead);

    byte[] bytes = Data.GetBuffer();
    int idx = 0;
    int size = (int) Data.Length;

    while (idx < size)
    {
        int found = Array.FindIndex(bytes, idx, size - idx, b => b == 0x0A);
        if (found == -1) break;
        Console.WriteLine(Encoding.UTF8.GetString(AWNSER, idx, found-idx);
        idx = found + 1;
    }

    if (idx > 0)
    {
        Buffer.BlockCopy(bytes, idx, bytes, 0, size - idx);
        Data.SetLength(size - idx);
    }

    Stream.BeginRead(AWNSER, 0, AWNSER.Length, HNDLR, null);
}

عميل:

bool sendRaw(SOCKET skt, void *buf, int bufsize)
{ 
    char *p = (char*) buf;
    while (buflen > 0)
    {
        int sent = send(skt, p, buflen, 0);
        if (sent == SOCKET_ERROR) return false;
        p += sent;
        buflen -= sent;
    }
    return true;
}

...

FILE *fp;
char AWNSER[256];
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);

if (WSAStartup(DllVersion, &wsaData) != 0) //no error
{
    cout << "Winsock startup failed";
}

SOCKADDR_IN addr;
int addrlen = sizeof(addr);
addr.sin_port = htons(123);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("199.166.177.22");

SOCKET Connection = socket(AF_INET, SOCK_STREAM, 0);
if (Connection == INVALID_SOCKET)
{
    /*ERROR*/
} 
else
{
    if (connect(Connection, (SOCKADDR*)&addr, addrlen) != 0)
    {
        /*ERROR*/
    }
    else
    {
        fp = _popen("dir", "r");
        while (fgets(AWNSER, 256, fp))
        {
            int len = strlen(AWNSER);
            while ((len > 0) && ((AWNSER[len-1] == '\r') || (AWNSER[len-1] == '\n'))) --len;
            AWNSER[len++] = '\n';
            cout.write(AWNSER, len);
            if (!sendRaw(Connection, AWNSER, len)) break;
        }
        _pclose(fp);
        //... 
    }
    closesocket(Connection);
}
:مؤلف
فوق
قائمة طعام