Merhaba, medium üzerinden yayınlayacağım ilk yazımı yazma fırsatım olduğu için çok memnunum. Bu yazımı yazılım alanında staja başladığımda benden ilk istenen uygulama üzerine yazmaya karar verdim çünkü, ilk olarak bu projeyi seçerek başta zorlansak bile daha sonra zorlukları aşabildiğimizi göstermek istedim sanırım. Bu uygulamada Tcp kullanarak lokal ağ üzerinden mesaj transferi gerçekleştireceğiz. İlk yazımı okuduğunuz için teşekkür ederim, hadi başlayalım.
TCP/IP Nedir?
Bu konuyu anlatırken çok derinlemesine incelemeyeceğiz, çünkü yazım konuyu açıklamaktan çok QT framework kurallarıyla lokal ağ üzerinde mesaj alıp verebileceğimiz bir soket uygulaması hazırlamak.
Tcp/Ip kısaltmasını hepimiz sık sık duymaktayız. Bu kısaltmanın bu kadar popüler olma nedeni internetin bu protokol üzerine kurulu olması.Bu ağ protokolünün diğer ağ protokollerinin yanından sıyrılıp her şeyin temeli olması sebebi olarak ise kimseye ait olmaması gösteriliyor. Diğer ağ protokolleri daha hızlı, daha kullanışlı bile olsa bizler kullanabilmek için protokolün sahibi şirkete telif hakkı ödemek durumunda kalabildiğimizden bahsediliyor.
Tcp(Transmission Control Protocol)/Ip(Internet Protocol) ağ protokolü bilgisayarlar arası kayıpsız veri transferi imkanını bize sunuyor. Server ve client arasında bağlantı sağlandıktan sonra veri transfer etmeye başlayabiliyoruz. Burada kritik olan konu ise bağlantının başlaması çünkü sever ve client arasında bağlantı sağlanmazsa veri transferi hiçbir şekilde gerçekleşmiyor. Bağlantı başlandıktan sonra ise bu protokol gereğince gönderilen her mesajın tam ve eksiksiz olarak gönderilip gönderilmediği kontrol ediyor. Bu bahsettiğim konu Tcp ve Udp protokolleri arasında bulunan en ciddi farklar olarak karşımıza çıkıyor. Tcp kullanılarak gönderilen mesajlar ise yalnız server-client arasında gerçekleşiyor. Bir clienttan başka bir clienta direk olarak veri yollayamıyoruz.
Tcp Server Sınıfının Hazırlanması
Bu hazırlık başlama aşamasında ilk olarak yeni bir proje açıyoruz. Arayüzde bağlantıyı gösterebilmek için bir widget projesi açmayı tercih ettim. Daha sonra .pro dosyasına aşağıdaki kod satırını ekliyoruz
QT += network
Bu kod satırı bize Tcp ile ilgili kütüphaneleri kullanma imkanı verecek. Daha sonra projeme yeni bir TcpServer ekledim, sınıfı eklerken base class olarak QObject’in seçili olduğunu belirtmem gerekiyor. Private olarak QTcpServer ve QTcpSocket sınıflarından birer obje oluşturdum daha sonra bu objelerin sinyal ve slotlarını bağlamak üzere fonksiyonlarımı yarattım header dosyam oluştu. StartServer adındaki fonksiyonumun içerisinde yeni bir bağlantı sağlamak için aşağıdaki kodu ekledim.
void TcpServer::startServer(){m_server = new QTcpServer{this}; // QTcpServer sıfından bir obje oluşturulduconnect(m_server, &QTcpServer::newConnection, this, &TcpServer::onNewConnection); // Yeni bir bağlantı sağlandığında onNewConnection fonksiyonu çalıştırıldı.m_server->listen(QHostAddress::LocalHost, 8080); // Kendi lokal sunucu üzerinden bir server başlatıldı.}
Yeni bir bağlantı sağlandığında ise onNewConnection içerisinde servera gelecek mesajları dinlemesi için bir socket objesi oluşturdum ve bu objeyi sinyal slot bağlantısı ile gelen mesajları onReadyRead slotuna yollaması için ayarladım.
void TcpServer::onReadyRead(){QByteArray data;data = m_socket->readAll(); // Gelen mesaj QByteArray türünden saklandıQString message = QString::fromStdString(data.toStdString());message.remove(0,4); // Gelen mesajın ilk 4 karakteri bu uygulamada işimize yaradamadığı için silindimessage = QString::number(m_socket->socketDescriptor()) + " >> " + message;qDebug() << m_socket->socketDescriptor();emit messageReceived(message); }
Son olarak bu sınıf için bahsetmem gereken fonksiyonum ise mesaj yollamak fonksiyonu. Bu fonksiyonu içerisinde aldığı QString parametreyi değişken türü dönüşümleri ile byte türüne çevirip karşı tarafa yollayacak şekilde düzenledim.
void TcpServer::sendMessage(QString message){QDataStream socketStream(m_socket);socketStream.setVersion(QDataStream::Qt_5_15);QByteArray byteArray = message.toUtf8();socketStream.setVersion(QDataStream::Qt_5_15);socketStream << byteArray;}
Tcp Server sınıfımız basitçe kullanılacak şekilde hazırlandığını düşünmekteyim bunu test edebilmek için Linux sistemi üzerinde NetCat komutunu kullanacağım ve basit seviyede bir arayüz hazırlayacağım. NetCat komutu kullanabilmek için nc kısaltmasını kullanıyoruz. Bu proje için nc <Ip adresi> <port no> şeklinde kullanabilirsiniz. Aşağıdaki komut yazıldıktan sonra bağlantı başlamakta
nc 127.0.0.1 8080
Tcp Server Sınıfının Hazırlanması
TcpClient sınıfımızda ise serverdan farklı olarak yalnızca bir QTcpSocket objesi oluşturdum. Bunun sebebi bu sınıf ile zaten var olan bir servera bağlanacağımız için artık server için bir obje oluşturmamıza gerek olmaması. Gelen mesajı yollamak ve mesaj okumak için server ile aynı fonksiyonları kullanabiliriz, ben öyle yaptım. Farklı olarak yaptığım şey ise bir server client bağlantısını sağlayan fonksiyon yaratmaktı.
void TcpClient::connectToHost(QString host, quint16 port){this->host = QHostAddress{host};this->port = port;socket = new QTcpSocket{this};connect(socket, &QTcpSocket::connected, this, &TcpClient::onConnected);connect(socket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected);connect(socket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this, &TcpClient::onError);socket->connectToHost(host, port);}
Bunların sonucunda iki sınıfımda lokal ağ üzerinde birbirleri ile veri transferi yapmak için hazır hale geldi. Ekran görüntüsünü sizlerle paylaşıyorum.
Proje dosyalarına erişmek için github bağlantısı;
Eleştiri ve yorumlarınız için benimle iletişime geçebilirsiniz, okuduğunuz için teşekkür ederim.
Linkedin hesabım:
https://www.linkedin.com/in/mert-can-iyli-425973205