OpenCvSharp for Network

OpenCV 2021. 12. 28. 22:45 |
반응형

C#에서 OpenCV Mat 데이터를 네트워크로 송수신 할 수 있도록 준비하는 과정을 시뮬레이션 해 보자.

아래 링크의 글에서 비트맵이 아닌 OpenCV Mat 데이터 송수신 과정이라 보면 된다.

2021.12.25 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 3

 

폼에 PictureBox, Button을 적당히 배치한다.

 

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using OpenCvSharp;
using System.IO;
 
namespace OpenCV
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            // 클라이언트 시뮬레이션
            // OpenCV Matrix를 생성하고 바이트 배열로 변환한다.
            Mat clientImage = new Mat("Barbara.jpg");
            byte[] data = clientImage.ToBytes(".jpg"); // ".jpg", ".png", ".bmp"
            //MemoryStream clientMemoryStream = clientImage.ToMemoryStream();
            //byte[] data = clientMemoryStream.ToArray();
 
            // 네트워크 시뮬레이션
            // ...
            // 클라이언트에서 OpenCV Matrix 바이트 배열(data)을 서버로 전송
 
            // 서버 시뮬레이션
            // 클라이언트에서 받은 바이트 배열(data)을 메모리 스트림으로
            // 변환 후 다시 비트맵으로 변환한다.
            MemoryStream serverMemoryStream = new MemoryStream(data);
            Bitmap bitmap = new Bitmap(serverMemoryStream);
            //Mat serverImage = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap);
            //Cv2.ImShow("Server Image", serverImage);
            pictureBox1.Image = bitmap;
        }
    }
}
 

 

클라이언트에서 Mat.ToBytes()가 핵심이다. (메모리 스트림으로 변환할 필요가 없다)

소스를 입력하고 빌드한다.

 

실행하면 버튼만 나타난다.

 

버튼을 클릭하면 이미지가 표시된다.

 

반응형
Posted by J-sean
:
반응형

2021.12.23 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 1

2021.12.24 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 2

 

위 두 링크에서 만든 프로그램을 개선해 클라이언트의 화면을 서버로 연속 전송, 영상으로 재생해 보자.

간단한 화면공유(Screen Share) 프로그램을 만드는 것이다.

 

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
140
141
142
143
144
145
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace Server
{
    public partial class Form1 : Form
    {
        TcpListener listener;
        TcpClient client;
        NetworkStream networkStream;
        MemoryStream memoryStream;
        Bitmap bitmap;
        IPHostEntry ipHostEntry;
        Thread thread;
 
        string serverIP;
        int serverPort;
        byte[] data;
        byte[] dataSizeFromClient;
        int receivedDataSize;
        int expectedDataSize;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
 
            serverPort = 7000;
            // 호스트 이름으로 검색되는 첫 번째 IP4 주소 확인
            string hostName = Dns.GetHostName();
            ipHostEntry = Dns.GetHostEntry(hostName);
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    serverIP = address.ToString();
                    break;
                }
            }
            listBox1.Items.Add("Server IP: " + serverIP);
 
            data = new byte[1048576 * 10]; // 1MB * 10
                                           // 클라이언트로 부터 전송되는 PNG 파일은 상황에 따라 4MB를 넘기도 한다.
            dataSizeFromClient = new byte[sizeof(int)];
        }
 
        private void ThreadProc()
        {
            listener = new TcpListener(IPAddress.Any, serverPort);
            //listener = new TcpListener(IPAddress.Parse("127.0.0.1"), serverPort);
            listener.Start();
 
            client = listener.AcceptTcpClient();
            listBox1.Items.Add("Client IP: " + client.Client.RemoteEndPoint.ToString().Split(':')[0]);
            networkStream = client.GetStream();
 
            while (true)
            {
                try
                {
                    receivedDataSize = 0;
 
                    if (networkStream.CanRead)
                    {
                        // 클라이언트로 부터 받아야 할 데이터 사이즈 정보 확인.
                        networkStream.Read(dataSizeFromClient, 0, dataSizeFromClient.Length);
                        expectedDataSize = BitConverter.ToInt32(dataSizeFromClient, 0);
                        //listBox1.Items.Add("Expected data size: " + (expectedDataSize / 1024).ToString() + "KB");
 
                        // 데이터 수신.                        
                        do
                        {
                            // 클라이언트로 부터 받아야 할 데이터 사이즈 만큼만 정확히 받는다.
                            receivedDataSize += networkStream.Read(data, receivedDataSize, expectedDataSize - receivedDataSize);
                            // Reads data from the NetworkStream and stores it to a byte array.
                        } while (expectedDataSize != receivedDataSize);
                        //while (networkStream.DataAvailable);
                        // NetworkStream.DataAvailable 은 네트워크 상황에 따라 정확하지 않을 가능성이 크다.
                        
                        //listBox1.Items.Add("Data size: " + (receivedDataSize / 1024).ToString() + "KB");
                        // 클라이언트로 부터 받은 데이터 사이즈가 버퍼 사이즈(10MB) 보다 크다면 버퍼 사이즈를 늘려야 한다.
                        // 그렇지 않으면 NetworkStream.Read()에서 ArgumentOutOfRangeException 예외 발생.
                    }
 
                    //listBox1.Items.Add("Data received: " + (receivedDataSize / 1024).ToString() + "KB");
                    memoryStream = new MemoryStream(data, 0, receivedDataSize);
                    // Initializes a new non-resizable instance of the MemoryStream class
                    // based on the specified region (index) of a byte array.            
                    bitmap = new Bitmap(memoryStream);
                    pictureBox1.Image = bitmap;
                }
                catch (Exception e)
                {
                    listBox1.Items.Add(e.Message);
                    listBox1.Items.Add(e.StackTrace);
                    break;
                }
            }
 
            listener.Stop();
            client.Close();
            networkStream.Close();
            memoryStream.Close();
        }
 
 
        private void button1_Click(object sender, EventArgs e)
        {
            // 클라이언트 접속 대기를 위한 스레드 생성(스레드는 1개만 생성한다)
            if (thread == null || !thread.IsAlive)
            {
                thread = new Thread(new ThreadStart(ThreadProc));
                thread.Start();
                listBox1.Items.Add("Waiting for a client...");
            }
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread != null && thread.IsAlive)
            {
                // TcpListener를 정지 시키지 않고 클라이언트 연결 대기시 프로그램을
                // 종료하려 하면 스레드가 종료되지 않아 프로그램이 종료되지 않는다.
                listener.Stop();
 
                // 클라이언트와 연결된 스레드를 종료하지 않으면 프로그램을 종료해도
                // 백그라운드에서 계속 실행된다.                
                thread.Abort();
            }
        }
    }
}
 

 

서버 코드를 입력하고 빌드한다.

Server.zip
0.00MB

 

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace Client
{
    public partial class Form1 : Form
    {
        TcpClient client;
        NetworkStream networkStream;
        MemoryStream memoryStream;
        Bitmap screen;
        Thread thread;
 
        string serverIP;
        int serverPort;
        byte[] data;
        byte[] dataSizeForServer;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            textBox1.Text = "192.168.0.100";
        }
 
        private void ThreadProc()
        {
            serverIP = textBox1.Text;
            serverPort = 7000;
            try
            {
                client = new TcpClient(serverIP, serverPort);
                networkStream = client.GetStream();
                listBox1.Items.Add("Connected to: " + client.Client.RemoteEndPoint.ToString().Split(':')[0]);
            }
            catch (Exception e)
            {
                listBox1.Items.Add(e.Message);
                listBox1.Items.Add(e.StackTrace);
 
                return;
            }
 
            try
            {
                while (true)
                {
                    screen = GetScreen();
                    memoryStream = new MemoryStream();
                    screen.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
                    data = memoryStream.ToArray();
                    pictureBox1.Image = screen;
 
                    if (networkStream.CanWrite)
                    {
                        // 보낼 데이터 사이즈를 서버에 미리 공유
                        dataSizeForServer = BitConverter.GetBytes(data.Length);
                        networkStream.Write(dataSizeForServer, 0, dataSizeForServer.Length);
 
                        // 데이터 송신
                        networkStream.Write(data, 0, data.Length);
                        //listBox1.Items.Add("Data sent: " + (data.Length / 1024).ToString() + "KB");
                    }
 
                    // Thread.Sleep()을 삭제하면 더 부드러운 화면을 볼 수 있다.
                    // 하지만 CPU 점유율이 크게 높아진다. 적절히 조정하자.
                    Thread.Sleep(100);
                }
            }
            catch (Exception e)
            {
                listBox1.Items.Add(e.Message);
                listBox1.Items.Add(e.StackTrace);
            }
 
            client.Close();
            networkStream.Close();
            memoryStream.Close();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            // 클라이언트 접속 대기를 위한 스레드 생성(스레드는 1개만 생성한다)
            if (thread == null || !thread.IsAlive)
            {
                thread = new Thread(new ThreadStart(ThreadProc));
                thread.Start();
                listBox1.Items.Add("Connecting to the server...");
            }
        }
 
        private Bitmap GetScreen()
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics g = Graphics.FromImage(bitmap);
            g.CopyFromScreen(0000, bitmap.Size);
            g.Dispose();
 
            return bitmap;
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread != null && thread.IsAlive)
            {
                // 스레드를 종료하지 않으면 백그라운드에서 계속 실행된다.
                thread.Abort();
            }
        }
    }
}
 

 

클라이언트 코드를 입력하고 빌드한다.

Client.zip
0.01MB

 

한 컴퓨터에서 서버, 클라이언트를 모두 실행한 화면

 

 

NetworkStream.DataAvailable 프로퍼티는 네트워크 상황에 따라 부정확한 경우가 많다. 그러므로 서버에서는 클라이언트로 부터 받을 데이터의 사이즈를 미리 확인하고 그 사이즈만큼 정확히 받는게 중요하다.

작은 크기의 데이터는 사이즈 정보 교환없이 한번에 송수신해도 별 문제는 없다. 하지만 이 프로그램처럼 수백 KB의 데이터를 주고 받는 경우 한번에 송수신이 되지 않을 가능성이 크다.

 

클라이언트에서는 서버로 데이터를 전송하기 전, 보낼 데이터 사이즈를 미리 공유해 서버에서 수신 준비할 수 있도록 한다.

MemoryStream으로 저장할 데이터 포맷을 ImageFormat.Jpeg로 바꾸면 ImageFormat.Png에 비해 훨씬 작은 사이즈의 데이터가 만들어지고 영상의 FPS를 향상시킬 수 있다. (PNG는 비손실 압축, JPEG는 손실 압축)

 

반응형
Posted by J-sean
:
반응형

2021.12.23 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 1 에서 만든 프로그램을 개선해 보자.

네트워크 접속 지연으로 발생할 수 있는 에러를 처리하고 스레드를 사용해 네트워크 접속 대기 시 freeze되는 부분을 개선했다.

 

폼 디자인은 2021.12.23 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 1 과 동일하다.

 

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace Server
{
    public partial class Form1 : Form
    {
        TcpListener listener;
        TcpClient client;
        NetworkStream networkStream;
        MemoryStream memoryStream;
        Bitmap bitmap;
        IPHostEntry ipHostEntry;
        Thread thread;
 
        string serverIP;
        int serverPort;
        byte[] data = new byte[1048576]; // 1MB
        byte[] dataSizeFromClient;
        int receivedDataSize;
        int expectedDataSize;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
 
            serverPort = 7000;
            // 호스트 이름으로 검색되는 첫 번째 IP4 주소 확인
            string hostName = Dns.GetHostName();
            ipHostEntry = Dns.GetHostEntry(hostName);
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    serverIP = address.ToString();
                    break;
                }
            }
            listBox1.Items.Add("Server IP: " + serverIP);
 
            listener = new TcpListener(IPAddress.Any, serverPort);
            //listener = new TcpListener(IPAddress.Parse("127.0.0.1"), serverPort);            
        }
 
        private void ThreadProc()
        {
            listener.Start();
 
            client = listener.AcceptTcpClient();
            listBox1.Items.Add("Client IP: " + client.Client.RemoteEndPoint.ToString().Split(':')[0]);
 
            networkStream = client.GetStream();
 
            receivedDataSize = 0;
            dataSizeFromClient = new byte[sizeof(int)];
 
            if (networkStream.CanRead)
            {
                // 클라이언트로 부터 받아야 할 데이터 사이즈 정보 확인.
                networkStream.Read(dataSizeFromClient, 0, dataSizeFromClient.Length);
                expectedDataSize = BitConverter.ToInt32(dataSizeFromClient, 0);
                listBox1.Items.Add("Expected data size: " + (expectedDataSize / 1024).ToString() + "KB");
 
                // 데이터 송신
                do
                {
                    receivedDataSize += networkStream.Read(data, receivedDataSize, data.Length - receivedDataSize);
                    // Reads data from the NetworkStream and stores it to a byte array.                    
                } while (networkStream.DataAvailable);
                // while (expectedDataSize > receivedDataSize);
            }
 
            listBox1.Items.Add("Data received: " + (receivedDataSize / 1024).ToString() + "KB");
            memoryStream = new MemoryStream(data, 0, receivedDataSize);
            // Initializes a new non-resizable instance of the MemoryStream class
            // based on the specified region (index) of a byte array.            
            bitmap = new Bitmap(memoryStream);
            pictureBox1.Image = bitmap;
 
            listener.Stop();
            client.Close();
            networkStream.Close();
            memoryStream.Close();
        }
 
 
        private void button1_Click(object sender, EventArgs e)
        {
            // 클라이언트 접속 대기를 위한 스레드 생성(스레드는 1개만 생성한다)
            if (thread == null || !thread.IsAlive)
            {
                thread = new Thread(new ThreadStart(ThreadProc));
                thread.Start();
                listBox1.Items.Add("Waiting for a client...");
            }
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread != null && thread.IsAlive)
            {
                // 클라이언트 접속 대기 종료
                listener.Stop();
                //thread.Abort();
            }
        }
    }
}
 

 

서버 코드를 작성하고 빌드한다.

 

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace Client
{
    public partial class Form1 : Form
    {
        TcpClient client;
        NetworkStream networkStream;
        MemoryStream memoryStream;
        Bitmap screen;
        Thread thread;
 
        string serverIP;
        int serverPort;
        byte[] data;
        byte[] dataSizeForServer;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            textBox1.Text = "192.168.0.100";
        }
 
        private void ThreadProc()
        {
            screen = GetScreen();
            // pictureBox1.Image = screen;
            // 위 명령을 여기서 실행하면 아래와 같은 에러가 발생한다. (이해할 수 없다.)
            // System.InvalidOperationException: 개체를 다른 곳에서 사용하고 있습니다.
            // 서버 접속(아래 try-catch) 이후 실행하면 된다.
 
            memoryStream = new MemoryStream();
 
            screen.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
            data = memoryStream.ToArray();
 
            serverIP = textBox1.Text;
            serverPort = 7000;
            try
            {
                client = new TcpClient(serverIP, serverPort);
            }
            catch (Exception e)
            {
                listBox1.Items.Add(e.Message);
                memoryStream.Close();
 
                return;
            }
 
            listBox1.Items.Add("Connected to: " + client.Client.RemoteEndPoint.ToString().Split(':')[0]);
            pictureBox1.Image = screen;
 
            networkStream = client.GetStream();
 
            if (networkStream.CanWrite)
            {
                // 보낼 데이터 사이즈를 서버에 미리 공유
                dataSizeForServer = BitConverter.GetBytes(data.Length);
                networkStream.Write(dataSizeForServer, 0, dataSizeForServer.Length);
 
                // 데이터 전송
                networkStream.Write(data, 0, data.Length);
                listBox1.Items.Add("Data sent: " + (data.Length / 1024).ToString() + "KB");
            }
 
            client.Close();
            networkStream.Close();
            memoryStream.Close();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            // 클라이언트 접속 대기를 위한 스레드 생성(스레드는 1개만 생성한다)
            if (thread == null || !thread.IsAlive)
            {
                thread = new Thread(new ThreadStart(ThreadProc));
                thread.Start();
                listBox1.Items.Add("Connecting to the server...");
            }
        }
 
        private Bitmap GetScreen()
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics g = Graphics.FromImage(bitmap);
            g.CopyFromScreen(0000, bitmap.Size);
            g.Dispose();
 
            return bitmap;
        }
    }
}
 

 

클라이언트 코드를 작성하고 빌드한다.

 

서버 실행 후 클라이언트 접속 대기 상태에서도 freeze 되지 않는다.

 

클라이언트 실행 후 서버 접속 시도 중인 상태에서도 freeze 되지 않는다. (서버를 실행하지 않고 테스트)

 

 

서버 접속에 실패하더라도 클라이언트는 종료되지 않고 에러 메세지만 보낸다.

 

서버, 클라이언트가 문제 없이 연결되면 정상 작동한다.

 

※ 참고

2021.12.25 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 3

 

반응형
Posted by J-sean
:
반응형

TcpListener, TcpClient, NetworkStream, MemoryStream등을 이용해 클라이언트의 화면을 서버로 전송하는 프로그램을 만들어 보자. (이 예제는 thread를 사용하지 않기 때문에 상황에 따라 프로그램이 freeze될 수 있다)

 

서버 폼에 PictureBox, ListBlox, Button을 적당히 배치한다.

 

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace Server
{
    public partial class Form1 : Form
    {
        TcpListener listener;
        TcpClient client;
        NetworkStream networkStream;
        MemoryStream memoryStream;
        Bitmap bitmap;
        IPHostEntry ipHostEntry;
 
        string serverIP;
        int serverPort;
        byte[] data = new byte[1048576]; // 1MB
        byte[] dataSizeFromClient;
        int receivedDataSize;
        int expectedDataSize;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
 
            serverPort = 7000;
            // 호스트 이름으로 검색되는 첫 번째 IP4 주소 확인
            string hostName = Dns.GetHostName();
            ipHostEntry = Dns.GetHostEntry(hostName);
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    serverIP = address.ToString();
                    break;
                }
            }
            listBox1.Items.Add("Server IP: " + serverIP);
 
            listener = new TcpListener(IPAddress.Any, serverPort);
            //listener = new TcpListener(IPAddress.Parse("127.0.0.1"), serverPort);            
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            listener.Start();
 
            client = listener.AcceptTcpClient();
            listBox1.Items.Add("Client IP: " + client.Client.RemoteEndPoint.ToString().Split(':')[0]);
 
            networkStream = client.GetStream();
 
            receivedDataSize = 0;
            dataSizeFromClient = new byte[sizeof(int)];
 
            if (networkStream.CanRead)
            {
                // 클라이언트로 부터 받아야 할 데이터 사이즈 정보 확인.
                networkStream.Read(dataSizeFromClient, 0, dataSizeFromClient.Length);
                expectedDataSize = BitConverter.ToInt32(dataSizeFromClient, 0);
                listBox1.Items.Add("Expected data size: " + (expectedDataSize / 1024).ToString() + "KB");
 
                // 데이터 송신
                do
                {
                    receivedDataSize += networkStream.Read(data, receivedDataSize, data.Length - receivedDataSize);
                    // Reads data from the NetworkStream and stores it to a byte array.                    
                } while (networkStream.DataAvailable);
                // while (expectedDataSize > receivedDataSize);
            }
 
            listBox1.Items.Add("Data received: " + (receivedDataSize / 1024).ToString() + "KB");
            memoryStream = new MemoryStream(data, 0, receivedDataSize);
            // Initializes a new non-resizable instance of the MemoryStream class
            // based on the specified region (index) of a byte array.            
            bitmap = new Bitmap(memoryStream);
            pictureBox1.Image = bitmap;
 
            listener.Stop();
            client.Close();
            networkStream.Close();
            memoryStream.Close();
        }
    }
}
 

 

서버 소스를 입력하고 빌드한다.

 

클라이언트 폼에 PictureBox, ListBox, Label, TextBox, Button을 적당히 배치한다.

 

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace Client
{
    public partial class Form1 : Form
    {
        TcpClient client;
        NetworkStream networkStream;
        MemoryStream memoryStream;
        Bitmap screen;
 
        string serverIP;
        int serverPort;
        byte[] data;
        byte[] dataSizeForServer;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            textBox1.Text = "192.168.0.100";
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            memoryStream = new MemoryStream();
            screen = GetScreen();
            pictureBox1.Image = screen;
            screen.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
            data = memoryStream.ToArray();
 
            serverIP = textBox1.Text;
            serverPort = 7000;
            client = new TcpClient(serverIP, serverPort);
            listBox1.Items.Add("Connected to: " + client.Client.RemoteEndPoint.ToString().Split(':')[0]);
 
            networkStream = client.GetStream();
 
            if (networkStream.CanWrite)
            {
                // 보낼 데이터 사이즈를 서버에 미리 공유
                dataSizeForServer = BitConverter.GetBytes(data.Length);
                networkStream.Write(dataSizeForServer, 0, dataSizeForServer.Length);
 
                // 데이터 전송
                networkStream.Write(data, 0, data.Length);
                listBox1.Items.Add("Data sent: " + (data.Length / 1024).ToString() + "KB");
            }
 
            client.Close();
            networkStream.Close();
            memoryStream.Close();
        }
 
        private Bitmap GetScreen()
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics g = Graphics.FromImage(bitmap);
            g.CopyFromScreen(0000, bitmap.Size);
            g.Dispose();
 
            return bitmap;
        }
    }
}
 

 

클라이언트 소스를 입력하고 빌드한다.

 

 

서버를 실행하면 IP주소가 표시된다.

 

클라이언트를 실행하고 서버 IP주소를 입력한다.

 

서버의 'Start Server' 버튼을 클릭하면 보안 경고가 나타난다. '액세스 허용' 버튼을 클릭한다.

 

클라이언트의 'Start Client' 버튼을 클릭한다.

 

서버 프로그램에는 접속된 클라이언트의 화면과 함께 클라이언트 IP주소, 전송될 데이터 사이즈, 실제 전송된 데이터 사이즈가 표시된다.

같은 컴퓨터에서 서버와 클라이언트를 동시에 실행했기 때문에 같은 IP주소가 표시된다.

 

 

클라이언트 프로그램에는 캡쳐한 화면과 함께 접속한 서버의 IP주소, 전송된 데이터 사이즈가 표시된다.

 

※ 참고

2021.12.24 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 2

2021.12.25 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 3

 

반응형
Posted by J-sean
:
반응형

간단히 화면을 캡쳐해 보자.

 

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
using System.Windows.Forms;
using System.Drawing;
 
namespace CS
{
    class Program
    {
        static void Main(string[] args)
        {
            Bitmap screen = GetScreen();
            screen.Save("screen.png"System.Drawing.Imaging.ImageFormat.Png);
        }
 
        static Bitmap GetScreen()
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics g = Graphics.FromImage(bitmap);
            g.CopyFromScreen(0000, bitmap.Size);
            g.Dispose();
 
            return bitmap;
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하면 Output 폴더에 screen.png 파일이 생성된다.

 

반응형
Posted by J-sean
:
반응형

콘솔에서 간단한 메세지를 주고 받는 서버, 클라이언트를 만들어 보자.

 

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
using System.Net;
using System.Net.Sockets;
 
namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.100"), 7777);
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
            Console.WriteLine("■ Server Info:");
            Console.WriteLine("IP Address : {0}", serverEndPoint.Address);
            Console.WriteLine("Port Number: {0}", serverEndPoint.Port);
            Console.WriteLine("AddressFamily : {0}", serverEndPoint.AddressFamily);
 
            // Associates a Socket with a local endpoint.
            server.Bind(serverEndPoint);
 
            // Places a Socket in a listening state.
            // Parameter: The maximum length of the pending connections queue.
            server.Listen(5);
 
            Console.WriteLine("Waiting for a client...");
 
            // Creates a new Socket for a newly created connection.
            Socket client = server.Accept();
 
            IPEndPoint clientEndPoint = (IPEndPoint)client.RemoteEndPoint;
            Console.WriteLine("Client connected: {0}", clientEndPoint.Address);
 
            byte[] sendBuff = Encoding.UTF8.GetBytes("Connected to the server.");
            // Sends the specified number of bytes of data to a connected Socket, using the specified SocketFlags.
            client.Send(sendBuff, sendBuff.Length, SocketFlags.None);
 
            byte[] recvBuff = new byte[256];
            // Receives data from a bound Socket into a receive buffer.
            // Return: The number of bytes received.
            if (client.Receive(recvBuff) != 0)
            {
                Console.WriteLine("Message from a client: " + Encoding.UTF8.GetString(recvBuff));
            } else
            {
                Console.WriteLine("No message.");
            }
 
            // Closes the Socket connection and releases all associated resources.
            client.Close();
            server.Close();
        }
    }
}
 

 

서버 소스

 

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
using System.Net;
using System.Net.Sockets;
 
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.100"), 7777);
            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
            // Establishes a connection to a remote host.
            client.Connect(serverEndPoint);
            Console.WriteLine("Connecting to the server...");
 
            byte[] recvBuff = new byte[256];
            client.Receive(recvBuff);
            Console.WriteLine("Message from the server: " + Encoding.UTF8.GetString(recvBuff));
 
            client.Send(Encoding.UTF8.GetBytes("Hello."));
 
            client.Close();
        }
    }
}
 

 

클라이언트 소스

 

서버를 실행 시키면 클라이언트를 기다린다.

 

클라이언트를 실행 시키면 대기중인 서버와 연결되고 메세지를 주고 받는다.

 

서버에도 클라이언트로부터 받은 메세지가 표시된다.

 

반응형
Posted by J-sean
:
반응형

IP 주소와 호스트 네임을 확인 해 보자.

 

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
using System.Net;
 
namespace CS
{
    using static System.Console;
 
    class Program
    {
        static void Main(string[] args)
        {
            // 인터넷 url로 IP 주소 확인
            string url = "www.naver.com";
            IPHostEntry ipHostEntry = Dns.GetHostEntry(url);
            WriteLine("■ IP addresses of " + url);
            foreach (IPAddress add in ipHostEntry.AddressList)
            {
                WriteLine(add.ToString());
            }
 
            // 호스트 네임으로 IP 주소 확인
            WriteLine();
            string hostName = Dns.GetHostName();
            ipHostEntry = Dns.GetHostEntry(hostName);
            WriteLine("■ All IP addresses of " + ipHostEntry.HostName);
            // WriteLine(hostName);            
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                WriteLine(address.ToString());
            }
 
            WriteLine();
            WriteLine("■ All IP6 addresses of " + ipHostEntry.HostName);
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                    WriteLine(address.ToString());
            }
 
            WriteLine();
            WriteLine("■ All IP4 addresses of " + ipHostEntry.HostName);
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    WriteLine(address.ToString());
            }
 
            WriteLine();
            WriteLine("■ All IP4 addresses of " + ipHostEntry.HostName);
            foreach (IPAddress address in ipHostEntry.AddressList)
            {
                if (address.ToString().Split('.').Count() == 4)
                    WriteLine(address.ToString());
            }
 
            // IP 주소로 호스트 네임 확인
            WriteLine();
            IPAddress ipAddress = IPAddress.Parse(ipHostEntry.AddressList[0].ToString());
            // IPAddress ipAddress = IPAddress.Parse("192.168.0.100"); // My internal IP address
            ipHostEntry = Dns.GetHostEntry(ipAddress);
            Console.WriteLine("■ Host name: " + ipHostEntry.HostName);
 
            // 웹사이트를 이용한 외부 IP 주소 확인
            WriteLine();
            try
            {
                string externalIP = new WebClient().DownloadString("http://ipinfo.io/ip").Trim();
                // or http://icanhazip.com
                WriteLine("■ External IP address: " + externalIP);
            }
            catch (Exception exc)
            {
                WriteLine(exc.Message);
            }
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

IP 주소 및 호스트 네임을 확인 할 수 있다.

 

반응형
Posted by J-sean
:

C# Default Value - 기본값

C# 2021. 12. 19. 13:00 |
반응형

default 키워드로 각 타입의 기본값을 확인 할 수 있다.

 

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CS
{
    using static System.Console;
 
    class Program
    {
        static void Main(string[] args)
        {
            int a = default;
            int b = default(int);
            WriteLine($"a: {a}");
            WriteLine($"b: {b}");
            WriteLine($"default(float): {default(float)}");
            WriteLine($"default(bool): {default(bool)}");
 
            WriteLine($"default(string): {default(string) ?? "null"}");
            string s = null;
            WriteLine($"string.IsNullOrEmpty(s): {string.IsNullOrEmpty(s)}");
 
            WriteLine("default(char): {0}"default(char== '\0' ? @"\0" : @"not \0");
            // char는 기본값으로 '\0'이 대입 되기 때문에 아래 명령은 아무것도 표시하지 않는다.
            // WriteLine($"default(char): {default(char)}");
            WriteLine("default(int[]): {0}"default(int[]) == null ? "null" : "not null");
        }
    }
}
 

 

 

 

반응형
Posted by J-sean
: