상세 컨텐츠

본문 제목

[C#] 소켓 통신 시 구조체,바이너리, 마샬링 등등 사용하기 관련

본문

반응형

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

 

출처: http://www.mkexdev.net/Article/Content.aspx?parentCategoryID=1&categoryID=21&ID=484

 

 

이번에는 소켓 통신 시 자주 사용되는 구조체를 주고 받는 것에 대해 질/답 형태의 글을 기록합니다
이전에 윈폼카페의 질문에 대한 답변입니다 (2008.01.03일 자료,  http://cafe.naver.com/winform/49)
------------------------------------------------------------------------------------------------------------------------

질문>>>>>

제목도 뭐라고 써야할지 좀 난감 ㅋ
요즘 C#으로 네떡좀 만져볼라는데 상당히 거시기합니다.

C/C++에서 다음과 같은 내용이 있습니다.

typedef struct Data{
        int a;
        char b;
        char str[30];
};

Data data;
...
char buffer[256];

memcpy(buffer, &data, sizeof(data));

이렇게 마지막에 memcpy를 해주면 구조체가 갖고있는 메모리를 그대로 복사해올 수 있죠.
혹은

void OnReceivePacket(char* packet){
    Data* recvData = (Data*)packet;
}

이 처럼 형 변환을 통해 간단히 Data 구조체를 얻어낼 수도 있구요.

그런데 아직까지 제가 찾아본 결과로는...
C#에서는 하나씩 변환해서 넣어주어야 하는 듯 합니다.

    public class Packet_CS_Hello {
        public Packet_CS_Hello(byte[] from)
        {
            size = BitConverter.ToUInt16(from, 0);
            id = BitConverter.ToUInt16(from, 2);

            data = BitConverter.ToUInt32(from, 4);
        }

        public UInt32 data;
        public ushort size;
        public ushort id;
    }

이 방법 말고 좀 더 깔끔한 (unsafe 말구 ^^) 방법은 없을까요?


답변 >>>>>

소켓 통신 시 구조체를 많이 주고 받기는 합니다
그 방법에 대한 질문 같은데요.....

샘플을 가지고 이야기 해 보겠습니다

다음과 같은 구조체를 정의 합니다

 

 
[Serializable]
 [StructLayout(LayoutKind.Sequential)]
 struct Data
 {
      [MarshalAs(UnmanagedType.U2, SizeConst = 2)]
      public ushort size;
      [MarshalAs(UnmanagedType.U2, SizeConst = 2)]
       public ushort id;
       [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
       public UInt32 data;
  };

 

이 구조체를 바이트 배열로 변환 하여 네트워크 저 넘어로 전달하고 전달받은 곳에서는 다시 구조체로 변환하여
사용하고자 합니다

일단 동군님처럼 

BitConvert 

를 이용해서 하나하나 끊어서 값을 찾아 낼 수 도 있습니다

 

 ushort size = BitConverter.ToUInt16(bytesForWrite, 0);
 ushort id = BitConverter.ToUInt16(bytesForWrite, 2);
 UInt32 data = BitConverter.ToUInt32(bytesForWrite, 4);

 Data receiverData1;
 receiverData1.size = size;
 receiverData1.id = id;
 receiverData1.data = data;
string result1 = String.Format("Size:{0},ID:{1},Data:{2}", receiverData1.size, receiverData1.id, receiverData1.data);
Console.WriteLine(result1);

 

물론 이 방법은 구조체 멤버들의 정확한 크기에 맞는 적절한 Converting 을 해 주어야 하는 불편함이 있습니다
또한 구조체 멤버의 종류가 다양하면 캐안습(?) 일 수 도 있습니다 ㅋㅋ

그 다음으로는 

BinaryFormatter 

를 이용할 수 도 있습니다
NetworkStream 에 구조체를 Serialize 해서 수신측에서는 다시 Deserialize 하여 구조체를 얻는 방법입니다
즉, 마샬링을 이용하는 방법입니다

 

 BinaryFormatter formatter = new BinaryFormatter();

 Data receiverData = (Data) formatter.Deserialize(networkStream);

 

물론 

unsafe 를 이용

한 방법도 가능합니다

 

Data receiveData;
unsafe
{
    fixed (byte* ptr = bytes)
    {
        receiveData= (Data )Marshal.PtrToStructure((IntPtr)ptr, typeof(Data ));
     }
}            
return receiveData; 

만일 Data가 구조체가 아니라 클래스라면 아래와 같이 해도 됩니다
Data receiveData;
 unsafe
 {
      fixed (byte* ptr = bytesForWrite)
      {
           Marshal.PtrToStructure((IntPtr)ptr, (Data)receiveData);
       }
  }

 

여기서 제시된 샘플 프로젝트를 첨부 하였습니다. 다운로드 하여 실행 해 보신 후 참고하시길 바랍니다

그리고 마지막으로 덧붙이자면,닷넷 환경에서 소켓을 굳이 고집할 필요는 없습니다
리모팅이나 닷넷 3.0 의 WCF 와 같은 닷넷 환경에 진보된 형태의 분산어플리케이션 구축도 고려해 볼 만 합니다
그러면 이와 같은 문제(?) 상황은 덜 하리라 보입니다

그럼.. 즐 ~ 프 하삼요~~

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: https://it-jerryfamily.tistory.com/entry/Program-C%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A0-%EB%A7%88%EC%83%AC%EB%A7%81-%EB%B0%A9%EB%B2%95-%EC%BD%98%EC%86%94%ED%99%94%EB%A9%B4?category=611730

 

 

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.

 

★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.

 

이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.

 

프로그램 설명

 

클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class DataPacket
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Name;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Subject;
 
    [MarshalAs(UnmanagedType.I4)]
    public int Grade;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string Memo;
}

 

 

실행 후

 

 

메시지 전송 후

 

 

프로그램 작성 순서

 

1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.

 

1
2
3
4
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

 

2. 서버 프로그램

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
class Program
{
    static void Main(string[] args)
    {
        TcpListener server = null;
 
        try
        {
            server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
            server.Start();
 
            byte[] buffer = new byte[8092];
             
            while(true)
            {
                Console.WriteLine("Waiting for a connection.....");
 
                TcpClient client = server.AcceptTcpClient();
                Console.WriteLine("\nConnected!!");
 
                NetworkStream stream = client.GetStream();
 
                DataPacket packet = new DataPacket();
                //buffer = null;
 
                while(stream.Read(buffer, 0, Marshal.SizeOf(packet)) != 0)
                {
                    unsafe
                    {
                        fixed(byte* fixed_buffer = buffer)
                        {
                            Marshal.PtrToStructure((IntPtr)fixed_buffer, packet);
                        }
                    }
 
                    string Name = packet.Name;
                    string Subject = packet.Subject;
                    Int32 Grade = packet.Grade;
                    string Memo = packet.Memo;
 
                     
                    Console.WriteLine("이 름 : {0}", Name);
                    Console.WriteLine("과 목 : {0}", Subject);
                    Console.WriteLine("점 수 : {0}", Grade);
                    Console.WriteLine("메 모 : {0}", Memo);
                    Console.WriteLine("");
                    Console.WriteLine("===========================================");
                    Console.WriteLine("");
                }
 
                stream.Close();
                client.Close();
            }
        }
        catch(SocketException se)
        {
            Console.WriteLine(se.Message.ToString());
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
        }
 
        Console.ReadLine();
    }
}
 
[StructLayout(LayoutKind.Sequential)]
class DataPacket
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Name;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Subject;
 
    [MarshalAs(UnmanagedType.I4)]
    public int Grade;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string Memo;
}

 

 

3. 클라이언트 프로그램

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class Program
{
    static void Main(string[] args)
    {
        try
        {
            string Name = string.Empty;
            string Subject = string.Empty;
            Int32 Grade = 0;
            string Memo = string.Empty;
 
            do
            {
                Console.Write("이름 : ");
                Name = Console.ReadLine();
 
                Console.Write("과목 : ");
                Subject = Console.ReadLine();
 
                Console.Write("점수 : ");
                string tmpGrage = Console.ReadLine();
                if (tmpGrage != "")
                    Grade = Convert.ToInt32(tmpGrage);
                else
                    Grade = 0;
 
                Console.Write("메모 : ");
                Memo = Console.ReadLine();
 
                if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(Subject))
                    break;
 
                // 전송할 데이타 가공하기
                DataPacket packet = new DataPacket();
 
                packet.Name = Name;
                packet.Subject = Subject;
                packet.Grade = Grade;
                packet.Memo = Memo;
 
                byte[] buffer = new byte[Marshal.SizeOf(packet)];
 
                unsafe
                {
                    fixed (byte* fixed_buffer = buffer)
                    {
                        Marshal.StructureToPtr(packet, (IntPtr)fixed_buffer, false);
                    }
                }
 
                // 데이타 전송하기
                TcpClient client = new TcpClient();
                client.Connect("192.168.0.12", 13000);
                Console.WriteLine("Connected...");
 
                NetworkStream stream = client.GetStream();
 
                stream.Write(buffer, 0, Marshal.SizeOf(packet));
                Console.WriteLine("{0} data sent\n", Marshal.SizeOf(packet));
 
                stream.Close();
                client.Close();
            } while (Name != "" && Subject != "");
        }
        catch (SocketException se)
        {
            Console.WriteLine(se.Message.ToString());
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
        }
        Console.WriteLine("\nPress enter key to continue....");
        Console.ReadLine();
    }
}
 
[StructLayout(LayoutKind.Sequential)]
class DataPacket
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Name;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Subject;
 
    [MarshalAs(UnmanagedType.I4)]
    public int Grade;
   
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string Memo;
}

 

 



출처: https://it-jerryfamily.tistory.com/entry/Program-C구조체를-이용한-소켓통신-마샬링-방법-콘솔화면?category=611730 [IT 이야기]

 

 

 

=======================

=======================

=======================

 

 

 

 

출처: https://it-jerryfamily.tistory.com/entry/Program-C%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A02-%EB%A7%88%EC%83%AC%EB%A7%81-%EB%B0%A9%EB%B2%95-%EC%BD%98%EC%86%94-%EB%B2%84%EC%A0%84?category=611730

 

 

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.

 

★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.

 

이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.

 

프로그램 설명

 

클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다. 메소드 Serialize(), Deserialize(ref byte[] data) 가 구조체에서 배열로, 배열에서 구조체로 변경해 주는 기능을 담당하고 있습니다.

 DataPacket.cs

 

 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]     struct DataPacket     {         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]         public string Name;          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]         public string Subject;          [MarshalAs(UnmanagedType.I4)]         public int Grade;          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]         public string Memo;          // Calling this method will return a byte array with the contents         // of the struct ready to be sent via the tcp socket.         public byte[] Serialize()         {             // allocate a byte array for the struct data             var buffer = new byte[Marshal.SizeOf(typeof(DataPacket))];              // Allocate a GCHandle and get the array pointer             var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);             var pBuffer = gch.AddrOfPinnedObject();              // copy data from struct to array and unpin the gc pointer             Marshal.StructureToPtr(this, pBuffer, false);             gch.Free();              return buffer;         }          // this method will deserialize a byte array into the struct.         public void Deserialize(ref byte[] data)         {             var gch = GCHandle.Alloc(data, GCHandleType.Pinned);             this = (DataPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(DataPacket));             gch.Free();         }     }

 

 

실행 후

 

 

메시지 전송 후

 

 

프로그램 작성 순서

 

1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.

 

 

using System.Net; using System.Net.Sockets; using System.Threading; using System.Diagnostics;

 

 

2. 서버 프로그램

 

 

        static void Main(string[] args)         {             TcpListener server = null;              try             {                 server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);                 server.Start();                  byte[] buffer = new byte[1024];                                  while (true)                 {                     Console.WriteLine("Waiting for a connection.....");                      TcpClient client = server.AcceptTcpClient();                     Console.WriteLine("\nConnected!!");                      NetworkStream stream = client.GetStream();                      while (stream.Read(buffer, 0, buffer.Length) != 0)                     {                         // deserializing;                         DataPacket packet = new DataPacket();                         packet.Deserialize(ref buffer);                          string Name = packet.Name;                         string Subject = packet.Subject;                         Int32 Grade = packet.Grade;                         string Memo = packet.Memo;                                                  Console.WriteLine("이 름 : {0}", Name);                         Console.WriteLine("과 목 : {0}", Subject);                         Console.WriteLine("점 수 : {0}", Grade);                         Console.WriteLine("메 모 : {0}", Memo);                         Console.WriteLine("");                         Console.WriteLine("===========================================");                         Console.WriteLine("");                     }                      stream.Close();                     client.Close();                 }             }             catch (SocketException se)             {                 Console.WriteLine(se.Message.ToString());             }             catch (Exception ex)             {                 Console.WriteLine(ex.Message.ToString());             }              Console.ReadLine();         }

 

 

3. 클라이언트 프로그램

 

 

        static void Main(string[] args)         {             try              {                 string Name = string.Empty;                 string Subject = string.Empty;                 Int32 Grade = 0;                 string Memo = string.Empty;                  do                 {                     // 1. 데이타 입력                     Console.Write("이름 : ");                     Name = Console.ReadLine();                      Console.Write("과목 : ");                     Subject = Console.ReadLine();                      Console.Write("점수 : ");                     string tmpGrage = Console.ReadLine();                     if (tmpGrage != "")                     {                         int outGrade = 0;                         if (Int32.TryParse(tmpGrage, out outGrade))                             Grade = Convert.ToInt32(tmpGrage);                         else                             Grade = 0;                     }                     else                         Grade = 0;                      Console.Write("메모 : ");                     Memo = Console.ReadLine();                      if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(Subject))                         break;                      // 2. 구조체 데이타를 바이트 배열로 변환                     DataPacket packet = new DataPacket();                     packet.Name = Name;                     packet.Subject = Subject;                     packet.Grade = Grade;                     packet.Memo = Memo;                      byte[] buffer = packet.Serialize();                      // 3. 서버에 접속                     TcpClient client = new TcpClient();                     client.Connect("192.168.0.12", 13000);                     Console.WriteLine("Connected...");                      NetworkStream stream = client.GetStream();                      // 4. 데이타 전송                     stream.Write(buffer, 0, buffer.Length);                     Console.WriteLine("{0} data sent", buffer.Length);                     Console.WriteLine("===============================\n");                      // 5. 스트림&소켓 닫기                     stream.Close();                     client.Close();                  } while (Name != "" && Subject != "");             }             catch (SocketException se)             {                 Console.WriteLine("SocketException : {0} ", se.Message.ToString());             }             catch(Exception ex)             {                 Console.WriteLine("Exception : {0} ", ex.Message.ToString());             }             Console.ReadLine();         }

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: https://it-jerryfamily.tistory.com/entry/Program-C%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A01-%EB%A7%88%EC%83%AC%EB%A7%81-%EB%B0%A9%EB%B2%95-%EC%BD%98%EC%86%94-%EB%B2%84%EC%A0%84?category=611730

 

 

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.

 

★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.

 

이번에는 바이너리 포매터 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.

 

프로그램 설명

 

클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다.

 DataPacket.cs

1
2
3
4
5
6
7
8
[Serializable]
struct DataPacket
{
    public string Name;
    public string Subject;
    public int Grade;
    public string Memo;
}

 

실행 후

 

메시지 전송 후

 

프로그램 작성 순서

 

1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.

1
2
3
4
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

 

2. 서버 프로그램

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
static void Main(string[] args)
{
    TcpListener server = null;
    try
    {
        server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
        server.Start();
 
        byte[] buffer = new byte[256];
 
        while(true)
        {
            Console.WriteLine("Waiting for a connection.....");
 
            TcpClient client = server.AcceptTcpClient();
            Console.WriteLine("\nConnected!!");
 
            NetworkStream stream = client.GetStream();                   
 
            while(stream.Read(buffer, 0, buffer.Length) != 0)
            {
                DataPacket packet = GetBindAck(buffer);
 
                string Name = packet.Name;
                string Subject = packet.Subject;
                Int32 Grade = packet.Grade;
                string Memo = packet.Memo;
 
                Console.WriteLine("이 름 : {0}", Name);
                Console.WriteLine("과 목 : {0}", Subject);
                Console.WriteLine("점 수 : {0}", Grade);
                Console.WriteLine("메 모 : {0}", Memo);
                Console.WriteLine("");
                Console.WriteLine("===========================================");
                Console.WriteLine("");
            }
 
            stream.Close();
            client.Close();
        }
    }
    catch(SocketException se)
    {
        Console.WriteLine("SocketException : {0}", se.Message);
    }
    catch(Exception ex)
    {
        Console.WriteLine("Exception : {0}", ex.Message);
    }
}
 
private static DataPacket GetBindAck(byte[] btfuffer)
{
    DataPacket packet = new DataPacket();
 
    MemoryStream ms = new MemoryStream(btfuffer, false);
    BinaryReader br = new BinaryReader(ms);
                 
    packet.Name = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(20)));
    packet.Subject = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(20)));
    packet.Grade = IPAddress.NetworkToHostOrder(br.ReadInt32());
    packet.Memo = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(100)));
 
    br.Close();
    ms.Close();
 
    return packet;
}
 
// 문자열 뒤쪽에 위치한 null 을 제거한 후에 공백문자를 제거한다.
private static string ExtendedTrim(string source)
{
    string dest = source;
    int index = dest.IndexOf('\0');
    if (index > -1)
    {
        dest = source.Substring(0, index + 1);
    }
 
    return dest.TrimEnd('\0').Trim();
}

 

3. 클라이언트 프로그램

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
static void Main(string[] args)
{
    try
    {
        string Name = string.Empty;
        string Subject = string.Empty;
        Int32 Grade = 0;
        string Memo = string.Empty;
 
        do
        {
            // 1. 데이타 입력
            Console.Write("이름 : ");
            Name = Console.ReadLine();
 
            Console.Write("과목 : ");
            Subject = Console.ReadLine();
 
            Console.Write("점수 : ");
            string tmpGrage = Console.ReadLine();
            if (tmpGrage != "")
            {
                int outGrade = 0;
                if (Int32.TryParse(tmpGrage, out outGrade))
                    Grade = Convert.ToInt32(tmpGrage);
                else
                    Grade = 0;
            }
            else
                Grade = 0;
 
            Console.Write("메모 : ");
            Memo = Console.ReadLine();
 
            if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(Subject))
                break;
 
            // 2. 구조체 데이타를 바이트 배열로 변환
            DataPacket packet = new DataPacket();
            packet.Name = Name;
            packet.Subject = Subject;
            packet.Grade = Grade;
            packet.Memo = Memo;
 
            byte[] buffer = GetBytes_Bind(packet);
 
            // 3. 데이타 전송
            TcpClient client = new TcpClient();
            client.Connect("192.168.0.12", 13000);
            Console.WriteLine("Connected...");
 
            NetworkStream stream = client.GetStream();
 
            stream.Write(buffer, 0, buffer.Length);
            Console.WriteLine("{0} data sent\n", buffer.Length);
 
            stream.Close();
            client.Close();
        } while (Name != "" && Subject != "");
    }
    catch (SocketException se)
    {
        Console.WriteLine("SocketException : {0} ", se.Message.ToString());
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception : {0} ", ex.Message.ToString());
    }
 
    Console.WriteLine("press the ENTER to continue...");
    Console.ReadLine();
}
 
 
// 패킷 사이즈
public const int BODY_BIND_SIZE = 20 + 20 + 4 + 100;
 
// 인증 패킷 구조체를 바이트 배열로 변환하는 함수
public static byte[] GetBytes_Bind(DataPacket packet)
{
    byte[] btBuffer = new byte[BODY_BIND_SIZE];
 
    MemoryStream ms = new MemoryStream(btBuffer, true);
    BinaryWriter bw = new BinaryWriter(ms);
 
    // Name - string
    try
    {
        byte[] btName = new byte[20];
        Encoding.UTF8.GetBytes(packet.Name, 0, packet.Name.Length, btName, 0);
        bw.Write(btName);
    }
    catch(Exception ex)
    {
        Console.WriteLine("Error : {0}", ex.Message.ToString());
    }
 
    // Subject - string
    try
    {
        byte[] btName = new byte[20];
        Encoding.UTF8.GetBytes(packet.Subject, 0, packet.Subject.Length, btName, 0);
        bw.Write(btName);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error : {0}", ex.Message.ToString());
    }
 
    // Grade - long
    bw.Write(IPAddress.HostToNetworkOrder(packet.Grade));
 
    // Memo - string
    try
    {
        byte[] btName = new byte[100];
        Encoding.UTF8.GetBytes(packet.Memo, 0, packet.Memo.Length, btName, 0);
        bw.Write(btName);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error : {0}", ex.Message.ToString());
    }
 
    bw.Close();
    ms.Close();
 
    return btBuffer;
}

 



출처: https://it-jerryfamily.tistory.com/entry/Program-C구조체를-이용한-소켓통신1-마샬링-방법-콘솔-버전?category=611730 [IT 이야기]

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

반응형

 

728x90

 

 

출처: https://it-jerryfamily.tistory.com/entry/Program-C%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A0-%EB%A7%88%EC%83%AC%EB%A7%81-%EB%B0%A9%EB%B2%95-%EC%9C%88%EB%8F%84%EC%9A%B0%ED%99%94%EB%A9%B4

 

 

[Program C#]구조체를 이용한 소켓통신1 - 마샬링 방법 - 윈도우 버전

.닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.

 

★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.

 

이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.

 

프로그램 설명

 

클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다.

 

클라스 파일은 DataPacket.cs 파일입니다.

 DataPacket.cs

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class DataPacket
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Name;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Subject;
 
    [MarshalAs(UnmanagedType.I4)]
    public int Grade;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string Memo;
}

 

 

실행 후

 

 

메시지 전송 후

 

 

프로그램 작성 순서

 

1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.

 

1
2
3
4
5
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;

 

2. 서버 프로그램

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
TcpListener server = null;           
public MainForm()
{
    InitializeComponent();
    FormClosing += new FormClosingEventHandler(WindowsFormClosing);
    InitStart();
}
 
private void WindowsFormClosing(object sender, FormClosingEventArgs s)
{
    if (server != null)
        server = null;
 
    Application.Exit();
}
private void InitStart()
{
    Thread socketworker = new Thread(new ThreadStart(socketThread));
    socketworker.IsBackground = true;
    socketworker.Start();
}
 
private void socketThread()
{
    try
    {
        server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
        server.Start();
 
        while(true)
        {
            TcpClient client = server.AcceptTcpClient();
            updateStatusInfo("Connected");
            Thread clientworker = new Thread(new ParameterizedThreadStart(clientThread));
            clientworker.IsBackground = true;
            clientworker.Start(client);
        }             
 
    }
    catch(SocketException se)
    {
        Debug.WriteLine("SocketException : {0}", se.Message);
    }
    catch(Exception ex)
    {
        Debug.WriteLine("Exception : {0}", ex.Message);
    }
}
 
private void clientThread(object sender)
{
    // 1. 데이타 받기
    TcpClient client = sender as TcpClient;
    NetworkStream stream = client.GetStream();
 
    byte[] buffer = new byte[8092];
    DataPacket packet = new DataPacket();
 
    while (stream.Read(buffer, 0, Marshal.SizeOf(packet)) != 0)
    {
        unsafe
        {
            fixed (byte* fixed_buffer = buffer)
            {
                Marshal.PtrToStructure((IntPtr)fixed_buffer, packet);
            }
        }
    }
 
    stream.Close();
    client.Close();
 
    // 2. 데이타 표시하기
    string Name = packet.Name;
    string Subject = packet.Subject;
    Int32 Grade = packet.Grade;
    string Memo = packet.Memo;
 
    Debug.WriteLine("{0} : {1} : {2} : {3}", Name, Subject, Grade, Memo);
 
    Invoke((MethodInvoker)delegate
    {
        int count = listView1.Items.Count;
        count++;
 
        ListViewItem i = new ListViewItem();
        i.Text = count.ToString();
        i.SubItems.Add(Name);
        i.SubItems.Add(Subject);
        i.SubItems.Add(Grade.ToString());
        i.SubItems.Add(Memo);
        i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        listView1.Items.Add(i);
 
        listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
    });
 
    // 3. 상태값 표시하기
    updateStatusInfo("Data Accepted");
}
 
private void updateStatusInfo(string content)
{
    Action del = delegate()
    {
        lblStatus.Text = content;
    };
    Invoke(del);
}
 
private void btnDataClear_Click(object sender, EventArgs e)
{
    if(MessageBox.Show("데이타를 모두 삭제 하시겠습니까?","질문", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
    {
        listView1.Items.Clear();
    }
}

 

 

3. 클라이언트 프로그램

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
public MainForm()
{
    InitializeComponent();
 
    btnSend.MouseEnter += new EventHandler(btnSend_MouseEnter);
    btnSend.MouseLeave += new EventHandler(btnSend_MouseLeave);
}
 
void btnSend_MouseEnter(object sender, EventArgs e)
{
    btnSend.UseVisualStyleBackColor = false;
    btnSend.BackColor = Color.FromArgb(255, 255, 165, 00);  // 배경색을 오렌지 색으로 변경함...
    btnSend.ForeColor = Color.White;                        // 글자색을 흰색으로 변경함
}
 
void btnSend_MouseLeave(object sender, EventArgs e)
{
    btnSend.UseVisualStyleBackColor = true;
    btnSend.BackColor = SystemColors.Control;               // 배경색을 시스템 기본색으로 변경함...
    btnSend.ForeColor = SystemColors.ControlText;           // 글자색을 시스템 기본색으로 변경함...
}
 
private void btnSend_Click(object sender, EventArgs e)
{
    Thread socketworker = new Thread(new ThreadStart(socketThread));
    socketworker.IsBackground = true;
    socketworker.Start();
}
 
private void socketThread()
{
    // 1. 데이타패킷 조합
    Debug.WriteLine("{0} : {1} : {2} : {3}", txtName.Text, txtSubject.Text, txtGrade.Text, txtMemo.Text);
 
    DataPacket packet = new DataPacket();
 
    packet.Name = txtName.Text;
    packet.Subject = txtSubject.Text;
 
    Int32 outNum;
    if(Int32.TryParse(txtGrade.Text, out outNum))
    {
        packet.Grade = Convert.ToInt32(txtGrade.Text);
    }
    else
    {
        packet.Grade = 0;
    }
     
    packet.Memo = txtMemo.Text;
 
    if (string.IsNullOrEmpty(packet.Name))
    {
        MessageBox.Show("[이 름]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
        Invoke((MethodInvoker)delegate
        {
            txtName.Focus();
             
        });
        return;
    }
 
    if (string.IsNullOrEmpty(packet.Subject))
    {
        MessageBox.Show("[과 목]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
        Invoke((MethodInvoker)delegate
        {
            txtSubject.Focus();
 
        });
        return;
    }
 
    if (packet.Grade == 0)
    {
        MessageBox.Show("[점 수]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
        Invoke((MethodInvoker)delegate
        {
            txtGrade.Focus();
 
        });
        return;
    }
 
    if (string.IsNullOrEmpty(packet.Memo))
    {
        packet.Memo = " ";
    }
 
    // 2. TcpClient 생성 및 설정
    TcpClient client = new TcpClient(txtServerIP.Text, Convert.ToInt32(txtServerPort.Text));
    NetworkStream stream = client.GetStream();
    updateStatusInfo("Connected");
 
    // 3. 전송하기
    byte[] buffer = new byte[Marshal.SizeOf(packet)];
 
    unsafe
    {
        fixed (byte* fixed_buffer = buffer)
        {
            Marshal.StructureToPtr(packet, (IntPtr)fixed_buffer, false);
        }
    }
 
    stream.Write(buffer, 0, Marshal.SizeOf(packet));
    updateStatusInfo(string.Format("{0} data sent", Marshal.SizeOf(packet)));
 
    // 4. 스트림과 소켓 닫기
    stream.Close();
    client.Close();
 
    // 5. listview 에 추가하기
    Invoke((MethodInvoker)delegate
    {
        int count = listView1.Items.Count;
        count++;
 
        ListViewItem i = new ListViewItem();
        i.Text = count.ToString();
        i.SubItems.Add(txtName.Text);
        i.SubItems.Add(txtSubject.Text);
        i.SubItems.Add(txtGrade.Text);
        i.SubItems.Add(txtMemo.Text);
        i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        listView1.Items.Add(i);
 
        listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
    });
}
 
private void updateStatusInfo(string content)
{
    Action del = delegate()
    {
        lblStatus.Text = content;
    };
    Invoke(del);
}
 



출처: https://it-jerryfamily.tistory.com/entry/Program-C구조체를-이용한-소켓통신-마샬링-방법-윈도우화면 [IT 이야기]

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: https://it-jerryfamily.tistory.com/entry/Program-C%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A02-%EB%A7%88%EC%83%AC%EB%A7%81-%EB%B0%A9%EB%B2%95-%EC%9C%88%EB%8F%84%EC%9A%B0-%EB%B2%84%EC%A0%84?category=611730

 

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.

 

★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.

 

이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.

 

프로그램 설명

 

클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다. 메소드 Serialize(), Deserialize(ref byte[] data) 가 구조체에서 배열로, 배열에서 구조체로 변경해 주는 기능을 담당하고 있습니다.

 DataPacket.cs

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct DataPacket
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Name;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Subject;
 
    [MarshalAs(UnmanagedType.I4)]
    public int Grade;
 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string Memo;
 
    // Calling this method will return a byte array with the contents
    // of the struct ready to be sent via the tcp socket.
    public byte[] Serialize()
    {
        // allocate a byte array for the struct data
        var buffer = new byte[Marshal.SizeOf(typeof(DataPacket))];
 
        // Allocate a GCHandle and get the array pointer
        var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        var pBuffer = gch.AddrOfPinnedObject();
 
        // copy data from struct to array and unpin the gc pointer
        Marshal.StructureToPtr(this, pBuffer, false);
        gch.Free();
 
        return buffer;
    }
 
    // this method will deserialize a byte array into the struct.
    public void Deserialize(ref byte[] data)
    {
        var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
        this = (DataPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(DataPacket));
        gch.Free();
    }
}

 

 

실행 후

 

 

메시지 전송 후

 

 

프로그램 작성 순서

 

1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.

 

1
2
3
4
5
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;

 

 

2. 서버 프로그램

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
public partial class MainForm : Form
{
    TcpListener server = null;
    public MainForm()
    {
        InitializeComponent();
        FormClosing += new FormClosingEventHandler(WindowsFormClosing);
        InitStart();
    }
 
    private void WindowsFormClosing(object sender, FormClosingEventArgs s)
    {
        if (server != null)
            server = null;
 
        Application.Exit();
    }
    private void InitStart()
    {
        Thread socketworker = new Thread(new ThreadStart(socketThread));
        socketworker.IsBackground = true;
        socketworker.Start();
    }
 
    private void socketThread()
    {
        try
        {
            server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
            server.Start();
 
            while (true)
            {
                TcpClient client = server.AcceptTcpClient();
                updateStatusInfo("Connected");
                Thread clientworker = new Thread(new ParameterizedThreadStart(clientThread));
                clientworker.IsBackground = true;
                clientworker.Start(client);
            }
        }
        catch (SocketException se)
        {
            Debug.WriteLine("SocketException : {0}", se.Message);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Exception : {0}", ex.Message);
        }
    }
 
    private void clientThread(object sender)
    {
        // 1. 데이타 받기
        TcpClient client = sender as TcpClient;
        NetworkStream stream = client.GetStream();
         
        byte[] buffer = new byte[8092];
        DataPacket packet = new DataPacket();
 
        while (stream.Read(buffer, 0, buffer.Length) != 0)
        {
            // deserializing;               
            packet.Deserialize(ref buffer);
        }
 
        stream.Close();
        client.Close();
 
        // 2. 데이타 표시하기
        string Name = packet.Name;
        string Subject = packet.Subject;
        Int32 Grade = packet.Grade;
        string Memo = packet.Memo;
 
        Debug.WriteLine("{0} : {1} : {2} : {3}", Name, Subject, Grade, Memo);
 
        Invoke((MethodInvoker)delegate
        {
            int count = listView1.Items.Count;
            count++;
 
            ListViewItem i = new ListViewItem();
            i.Text = count.ToString();
            i.SubItems.Add(Name);
            i.SubItems.Add(Subject);
            i.SubItems.Add(Grade.ToString());
            i.SubItems.Add(Memo);
            i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            listView1.Items.Add(i);
 
            listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
        });
 
         
        // 3. 상태값 표시하기
        updateStatusInfo("Data Accepted");
    }
 
    private void updateStatusInfo(string content)
    {
        Action del = delegate()
        {
            lblStatus.Text = content;
        };
        Invoke(del);
    }
 
    private void btnDataClear_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show("데이타를 모두 삭제 하시겠습니까?", "질문", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
        {
            listView1.Items.Clear();
        }
    }
 
    private void btnClose_Click(object sender, EventArgs e)
    {
        Application.Exit();
    }
}

 

 

3. 클라이언트 프로그램

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    public MainForm()
    {
        InitializeComponent();
 
        btnSend.MouseEnter += new EventHandler(btnSend_MouseEnter);
        btnSend.MouseLeave += new EventHandler(btnSend_MouseLeave);
    }
 
    void btnSend_MouseEnter(object sender, EventArgs e)
    {
        btnSend.UseVisualStyleBackColor = false;
        btnSend.BackColor = Color.FromArgb(255, 255, 165, 00);  // 배경색을 오렌지 색으로 변경함...
        btnSend.ForeColor = Color.White;                        // 글자색을 흰색으로 변경함
    }
 
    void btnSend_MouseLeave(object sender, EventArgs e)
    {
        btnSend.UseVisualStyleBackColor = true;
        btnSend.BackColor = SystemColors.Control;               // 배경색을 시스템 기본색으로 변경함...
        btnSend.ForeColor = SystemColors.ControlText;           // 글자색을 시스템 기본색으로 변경함...
    }
 
    private void btnSend_Click(object sender, EventArgs e)
    {
        Thread socketworker = new Thread(new ThreadStart(socketThread));
        socketworker.IsBackground = true;
        socketworker.Start();
    }
 
    private void socketThread()
    {
        // 1. 데이타패킷 조합
        Debug.WriteLine("{0} : {1} : {2} : {3}", txtName.Text, txtSubject.Text, txtGrade.Text, txtMemo.Text);
 
        DataPacket packet = new DataPacket();
 
        packet.Name = txtName.Text;
        packet.Subject = txtSubject.Text;
 
        Int32 outNum;
        if (Int32.TryParse(txtGrade.Text, out outNum))
        {
            packet.Grade = Convert.ToInt32(txtGrade.Text);
        }
        else
        {
            packet.Grade = 0;
        }
 
        packet.Memo = txtMemo.Text;
 
        if (string.IsNullOrEmpty(packet.Name))
        {
            MessageBox.Show("[이 름]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
            Invoke((MethodInvoker)delegate
            {
                txtName.Focus();
 
            });
            return;
        }
 
        if (string.IsNullOrEmpty(packet.Subject))
        {
            MessageBox.Show("[과 목]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
            Invoke((MethodInvoker)delegate
            {
                txtSubject.Focus();
 
            });
            return;
        }
 
        if (packet.Grade == 0)
        {
            MessageBox.Show("[점 수]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
            Invoke((MethodInvoker)delegate
            {
                txtGrade.Focus();
 
            });
            return;
        }
 
        if (string.IsNullOrEmpty(packet.Memo))
        {
            packet.Memo = " ";
        }
 
        // 2. TcpClient 생성 및 설정
        TcpClient client = new TcpClient(txtServerIP.Text, Convert.ToInt32(txtServerPort.Text));
        NetworkStream stream = client.GetStream();
        updateStatusInfo("Connected");
 
        // 3. 전송하기
        byte[] buffer = packet.Serialize();
 
        stream.Write(buffer, 0, buffer.Length);
        updateStatusInfo(string.Format("{0} data sent", buffer.Length));
 
        // 4. 스트림과 소켓 닫기
        stream.Close();
        client.Close();
 
        // 5. listview 에 추가하기
        Invoke((MethodInvoker)delegate
        {
            int count = listView1.Items.Count;
            count++;
 
            ListViewItem i = new ListViewItem();
            i.Text = count.ToString();
            i.SubItems.Add(txtName.Text);
            i.SubItems.Add(txtSubject.Text);
            i.SubItems.Add(txtGrade.Text);
            i.SubItems.Add(txtMemo.Text);
            i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            listView1.Items.Add(i);
 
            listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
        });
    }
 
    private void updateStatusInfo(string content)
    {
        Action del = delegate()
        {
            lblStatus.Text = content;
        };
        Invoke(del);
    }
 
}



출처: https://it-jerryfamily.tistory.com/entry/Program-C구조체를-이용한-소켓통신2-마샬링-방법-윈도우-버전?category=611730 [IT 이야기]

 

 

 

 

=======================

=======================

=======================

 

 

 

 
#기타관련링크
 

 

=======================

=======================

=======================

 

 

 

 

 

 

 

반응형


관련글 더보기

댓글 영역