using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MYTCP
{
//라이브러리 형태로 작성될 크래스.
//TCP클라이언트로 접속할 수 있는 클래스를 작성.
public class Client
{
//이벤트
//연결이되면 연결을 알려주는 이벤트
public delegate void ConnectedHandler(Socket s);
public delegate void DisConnectedHandler(string disconnectMsg);
public delegate void ReceivedHandler(byte[] bytes);
public event ConnectedHandler OnConnected;
public event DisConnectedHandler OnDisConnected;
public event ReceivedHandler OnReceived;
private Socket socket = null;
private string ip = "";
private int port = 43210;
private Thread thread = null;
private bool stop = false; //클라이언트가 연결이 종료됬는지.연결이 되있는 상태인지..
public Client(string ipAddress,int port)
{
this.ip = ipAddress;
this.port = port;
//ip주소와,port를 할당.
//127.120.120.255
//데이터 중복없이 신뢰성있는 양방향 연결 기반의 바이트스트림
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
//클라이언트 연결을 시작
public void Start()
{
try
{
//IPEndPoint클래스란? 끝점,즉 연결될 곳의 IP주소와 Port를 가지고있는 클래스
//IP주소->어떠한 컴퓨터(서버)로 접속을 요청할 것인지..
//PORT ->서버의 어떠한 프로그램에 접속을 요청할 것인지.,
IPEndPoint remoteEp = new IPEndPoint(IPAddress.Parse(ip), port);
socket.Connect(remoteEp);//서버에게 연결을 요청하게됨..->Connect 동기적으로 요청.->서버 한대만을,서버프로그램이라면 BeginConnect함수를 사용.
//실패하면
if (OnConnected != null)
{
//연결이되면 이벤트를 통해서 사용하는 곳에 알려준다.
OnConnected(socket);
}
//서버와 송수신 즉 데이터를 주고받아야됨.
thread = new Thread(ReceiveMassage);
thread.IsBackground = true;//프로그램이 종료되면
thread.Start();
}
catch (Exception)
{
//서버와 연결실패시
throw;
}
}
//데이터수신 함수
private void ReceiveMassage()
{
//클라이언트 연결이 끊긴게아니라면 계속해서 반복해서 수신하도록..
while(!stop)
{
try
{
//네트워크에서 바이트형태로 데이터를 주고
byte[] buffer = new byte[1024];//1024바이트
int bytesRead = socket.Receive(buffer,0,buffer.Length,SocketFlags.None);//데이터 수신.
if (bytesRead<=0)
{
throw new SocketException();
}
//buffer 실질적으로 데이터가 쓰인것을
Array.Resize(ref buffer, bytesRead);
if(OnReceived!=null)
{
OnReceived(buffer);
}
}
catch
{
if(OnDisConnected!=null)
{
OnDisConnected("Disconnected");
}
//소켓연결 끊는작업
if (socket!=null)
{
socket.Close();
}
break;
}
}
//클라이언트 연결이 끊겼거나 또는 예외가 발생했을 때.
this.Stop();
}
public void SendMessage(string message)
{
int bytesSend = socket.Send(Encoding.UTF8.GetBytes(message));//UTF8->Bytes
}
//직접적으로 로그아웃또는
public void Stop()
{
stop = true;
if(socket!=null)
{
socket.Close();
socket.Dispose();
}
socket = null;
//수신하는 쓰레드도 정지
if(thread!=null)
{
thread.Abort();
}
thread = null;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MYTCP
{
public partial class Form1 : Form
{
//클라이언트가 주기적으로 메시지를 보내기위해서
//Timer
//소스코드는 앞서저기가
bool timerStop = false;
System.Timers.Timer timer = null;
public delegate void AsncMethodCaller(Client cnt);
//
DateTime receivedSuccessTime = DateTime.Now.AddMilliseconds(10 * 1000);//현재시간+10초
public Form1()
{
InitializeComponent();
}
Client client = null;
private void button1_Click(object sender, EventArgs e)
{
Start();
}
private void Start()
{
if(client == null)
{
receivedSuccessTime = DateTime.Now.AddMilliseconds(10 * 1000);
client = new Client(textBox1.Text, Int32.Parse(textBox2.Text));
client.OnConnected += TcpConneted;
client.OnDisConnected += TcpDisConnected;
client.OnReceived += TcpReceived;
client.Start();//서버와의 연결이 이뤄지게된다.
//클라이언트가 주기적으로 메시지를 보내기위해서
timerStop = false;
timer = new System.Timers.Timer();
timer.Interval = 10 * 1000;//테스트
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elasped);
timer.AutoReset = true;
timer.Start();
}
}
//주기적으로 요청
private void timer_Elasped(object sender,System.Timers.ElapsedEventArgs e)
{
if(!timerStop)
{
//시간비교차를 이용해서 연결이 송수신을 통해서 정상적인..
bool validConnection = ValidConnection(receivedSuccessTime, 15);
if (validConnection&& client!=null)
{
//주기적으로 메시지를 보내고
//비동기적으로
AsncMethodCaller asncMethodCaller = new AsncMethodCaller(DoPolling);
asncMethodCaller.BeginInvoke(client, null, null);
//보낸게 일정시간내에 도착을 하면... 연결이 정상이라고 판단을 할수있다.
}
else
{
//연결이 비정상적이면
Stop();
//재연결을 하겠다?
Start();
}
}
}
//메시지를 실질적으로 보내게될 함수,
private void DoPolling(Client cnt)
{
if(client!=null)
{
client.SendMessage("polling123");
}
}
//15초내로
private bool ValidConnection(DateTime dt,int limitTime)
{
//마지막으로 수신한 시간과 현재시간차를 계산.
int diffSeconds = Convert.ToInt32(DateTime.Now.Subtract(dt).TotalSeconds);//총시간중에 초단위로 시간차를
if(diffSeconds> limitTime)
{
return false;
}
else
{
//폴링이라던지 기타데이터를 수신하게되면
return true;
}
}
private void TcpConneted(Socket s)
{
this.BeginInvoke(new Action(() =>
{
richTextBox1.Text += "[Local]서버접속 성공.\r\n";
}));
}
private void TcpDisConnected(string disconnectMsg)
{
this.BeginInvoke(new Action(() =>
{
richTextBox1.Text += "[Local]서버접속 해제됨.\r\n";
}));
this.TimerStop();
client = null;
}
private void TcpReceived(byte[] bytes)
{
receivedSuccessTime = DateTime.Now;//데이터를 수신한 시각
this.BeginInvoke(new Action(() =>
{
richTextBox1.Text += "[Local]수신메시지-" + Encoding.UTF8.GetString(bytes) + ".\r\n";
}));
}
private void button2_Click(object sender, EventArgs e)
{
Stop();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Stop();
}
private void Stop()
{
this.TimerStop();
if (client != null)
{
client.Stop();
}
client = null;
}
private void button3_Click(object sender, EventArgs e)
{
if(client!=null)
{
client.SendMessage(textBox3.Text);//클라이언트에서 서버로 메시지전송.
}
}
//대문자소문자 섞어서 쓰는데.. 통일
private void TimerStop()
{
timerStop = true;
if(timer!=null)
{
timer.Elapsed-= new System.Timers.ElapsedEventHandler(timer_Elasped);
timer.Stop();
timer.Dispose();
timer = null;
}
}
}
}
Source : C#.Net 0.5년차~3년차(파트2)
'C#' 카테고리의 다른 글
데이터 바인딩 (0) | 2023.06.28 |
---|---|
dictionary 설명과 dictionary을 활용한 2문제 (0) | 2023.06.21 |
전기제어 PLC(Programmable Logic Controller) (0) | 2023.06.19 |
C# 파일과 디렉터리 (0) | 2023.06.19 |
dynamic (0) | 2023.06.18 |