PORT HABERLEŞME SERİ PORT FARUK BOZAN farukbozan@javatiryakileri.com bozanfaruk@gmail.com
Merhaba değerli Java dostları. Bu yazımızda port haberleşme konusuna değineceğiz. Yalnız şu noktaya dikkatinizi çekmek istiyorum. Port haberleşme iki şekilde yapılabilir. Birincisi sanal portlardır. Örneğin; bazı programların ağ üzerinden haberleşmek için kendilerine özel port numaraları vardır. MySQL 3306 numaralı portu, Tomcat ise 8080 numaralı portu kullanır. Bu numaralar yukarıda da bahsettiğim gibi sanaldır. Yani fiziksel bir öğe değildir. İkinci ayrım ise fiziksel portlardır. Yani bilgisayarın herhangi bir noktasında bulunan bağlantı noktasıdır. Bizim bu yazımızda işleyeceğimiz port konusu fiziksel port kısmına girmektedir. Fiziksel portlar da kendi aralarında paralel ve seri olmak üzere ikiye ayrılırlar. Paralel portlarda aynı anda birden fazla bilgi biti gönderilebilir. Seri port işlemlerinde ise aynı anda sadece 1 bilgi biti gönderilebilir. Bizim bu yazımızda değineceğimiz port seri port. Yalnız hiç endişe etmenize gerek yok çünkü; sadece birkaç satır kod değişikliği ile aynı işlemler paralel portlarla da yapılabilir. Hiç vakit kaybetmeden hemen API' ye göz atalım. Java da fiziksel port haberleşmesi için Java COMM API' si bulunur. Bunun içerisinde bulunan sınıf ve arayüzlerle gererli işlemler yapılır. Yalnız karşımıza şöyle bir problem çıkmaktadır. Sun, COMM API' nin Windows işletim sistemleri için olan desteğini kesmiştir. Dolasıyla Windows işletim sistemleri için işlem yapma istediğinizde 3. parti API bulmamız gerekecek. Dolasıyla benim bulmam gerek ti :). Kısa bir aramanın ardından RXTX adında bir api buldum ve muhtemelen siz de bulacaksanız. Peki COMM ile RXTX arasındaki fark nedir? Açıkçası ben bir fark bulamadım. Daha doğrusu tek fark Windows ortamında da RXTX API' sinin çalışması. Bunun dışında kodlarda, sınıflarda, arayüzlerde bir fark göremedim. Yavaş yavaş örneğimize geçelim. Bu yazıda temel işlemler anlatılacaktır. Yani eğer uygulamamıza güzel bir arayüz bekliyorsanız hayal kırıklığına uğramanız muhtemel. Arayüz işi size kaldı bu durumda :). RXTX jar dosyasını indirdikten sonra ve NetBeans ile de güzel bir Java Application açtıktan sonra library bölümüne sağ tıklayıp Add Jar/Folder komutu verdikten sonra jar dosyamızı belirtiyoruz. Bu kadar basit artık kodlara geçebiliriz. Önce hemen listener hakkında bilgi verelim. Olaya 1000 feetten bakınca temelde okuma ve yazma işlemlerinin olduğunu hemen görüyoruz. Dolasıyla okuma ve yazma işlemleri için portu dinlememiz gerekiyor. Müsait olduğunda yazma yani bilgi gönderme işlemini yapacağız. Bilgi geldiğinde ise yine bunu listener ile dinleyip okuyacağız. Anlık işlemler olacak yani. Aşağıdaki ifadeyi yazmamız gerekiyor. public class trxtx implements SerialPortEventListener TRXTX sınıfımızın adı, burada herhangi bir problem yok sanırım. SerialPortEventListener ifadesi ile bu arayüzü kullanıyoruz. Daha önce değindiğim gibi eğer paralel port kullanıyorsak yapılacak şey belli. Bu defa ParalelPortEventListener arayüzünü kullanmak. Biraz beyin fırtınası ile çok rahat bir paralel port uygulaması yazabiliriz. Arayüzü kullandıktan sonra NetBeans kırmızı uyarıları gözümüze sokmaya çalışacak. Nedeni çok basit. Eğer bir arayüzü kullanıyorsak onun gerekli olan metotlarını override yani tekrar yazmamız gerekecek. Bu defa aşağıdaki gibi bir kod bloğu oluşuyor. @Override public void serialevent(serialportevent e) if(e.geteventtype() == SerialPortEvent.DATA_AVAILABLE) İşte override etmemiz gereken metot. İçerik hariç geri kalanı aynen yukarıdaki gibi olmalıdır. Yoksa metot override edilmiş olmaz. Metot içerisine alınan e nesnesi ile de işlemleri gerçekleştireceğiz. Yukarıdaki koda göre eğer olay, porta bilgi geldiğinde tetiklenmektedir.
Yani okuma yapmamız lazım. DATA_AVAILABLE yerine çeşitli parametreleri deneyerek kendiniz farklı uygulamalar yazabilirsiniz. Böylece port dinlemeyi en başta aradan çıkardık. Sanki bir problem var gibi. Port dinliyoruz ama ortada dinlenecek port yok hemen port bulalım. public Vector<String> portlistesibul() Vector<String> portlistesi = new Vector<String>(); portlar = CommPortIdentifier.getPortIdentifiers(); yedekportlar = CommPortIdentifier.getPortIdentifiers(); while(portlar.hasmoreelements()) CommPortIdentifier tempport = (CommPortIdentifier)portlar.nextElement(); portlistesi.addelement(tempport.getname()); return portlistesi; return null; Yukarıdaki kod bloğunda mevcut portlar SERİ PARALEL ayrımı yapılmaksızın alınmaktadır. CommPortIdentifier.getPortIdentifiers() metodur bize bu işlemi sağlamaktadır. Portlar değişkeni mevcut portların sadece isimlerini almak, yedekportlar değişkeni ise aradığımız portu bulmak için kullanılmaktadır. While döngüsü içerisinde her portun adı tek tek listeye eklenmektedir. Son olarak da liste içerisinde String değişkenler olan Vector ile döndürülmüştür. Burada son dikkat çekeceğim son nokta CommPortIdentifier.getPortIdentifiers() ifadesinin Enumeration tipte veri döndürmesidir. Peki diyelimki listemizde birden çok port var ve hangisi bizim kullanacağımız port. Hemen bunun cevabını da kodlayalım. public void portbul() while(yedekportlar.hasmoreelements()) CommPortIdentifier tempport = (CommPortIdentifier)yedekPortlar.nextElement(); if((tempport.getporttype() == CommPortIdentifier.PORT_SERIAL) && (tempport.getname().equals( COM4 ))) port = tempport;
Daha önce de yazdığım gibi yedekportlar aradığımız portu bulmak için kullanılacak. Yedek portlardaki tüm elemanlar üzerinde geziniyoruz. Eğer o an üzerinden geçilen port seri port(tempport.getporttype() == CommPortIdentifier.PORT_SERIAL) ve adı da(tempport.getname().equals( COM4 )) bizim aradığımız port adı ise kullanacağımız port olarak ayarlıyoruz. Siz COM4 yerine başka değerler de verebilirsiniz ama; eğer bu değer mevcut portlar içerisinde yoksa herhangi bir atama yapılmayacaktır. Tavsiyem uygulama geliştirme boyunca COM3 portunu kullanmanız. Bu port hemen hemen hatta belki de her bilgisayarda bulunan sabit porttur ve modeme ayrılmıştır. Yani birkaç basit modem komutunu bilirseniz çok rahat modemle konuşabilirsiniz. Şimdi sıra bulunan portun açılma işleminde. public void seriportac() seriport = (SerialPort)port.open("RXTX", 2000); seriport.setserialportparams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); seriport.addeventlistener(this); seriport.notifyondataavailable(true); is = seriport.getinputstream(); os = seriport.getoutputstream(); SeriPort değişkenimiz bir önceki koddan bulduğumuz portun açılması ile aktif oluyor. Open metodundaki ilk parametre çalışma adıdır. Vereceğiniz değer pek önemli değil. İkinci parametre ise portun açılma işleminin kaç ms bekleneceğidir. Burada 2000 değeri verilmiştir. Yani 2 sn boyunca portu bekliyoruz, açılmazsa sağlık olsun diyoruz :). sonra seri portun ayarlarını yapıyoruz. Burada tavsiyem seri port ve RS-232 konularını biraz araştırmanız. Port hızı olarak 9600 verilmiştir. Data biti 8, stop biti 1 bit olarak ayarlanmıştır. Parity bit ise kullanılmamıştır. Daha sonra sınıfın başında kullandığımız listeneri ekliyoruz ve artık bu seri portumuz olayları beklemektedir. seriport.notifyondataavailable(true) ile de okunacak veri olduğunda seri portumuz uyarılmaktadır. Eğer bu kodu yazmazsanız bilgi geldiğinde portumuz haberdar olmayacaktır. Daha sonrada yazım ve okuma işlemleri için kanallar açılmaktadır. Uygulamanın sonunda close() metotları ile portları, bağlantıları kapatmayı unutmamamız gerekiyor aksi halde portlar diğer uygulamalar tarafından kullanılamayabilir. public synchronized void veriyaz(final byte[] tampon) os.write(tampon); os.flush(); System.err.println("Bilgi yazildi>>>" + new String(tampon)); catch(ioexception e)
Bu kodda çok basit bir yazma işlemi yapıldı. Çok da korkulacak bir işlem değil yani. Dikkat ederseniz parametre olarak byte[] alınmaktadır. Eğer String bir bilgi göndermek isterseniz. Static metotlar yardımı ile ifadenin byte[] karşılığı elinize geçecektir. public synchronized void verioku() byte[] tampon = new byte[is.available()]; while (is.available() > 0) is.read(tampon); String okunanbilgi = new String(tampon); System.err.println("Bilgi okundu>>>" + okunanbilgi); Burada da mevcut bilginin büyüklüğü kadar byte tamponu oluşturup bilgiyi buraya okuyoruz. Daha sonra ekrana çıktı olarak veriyoruz. Dikkat ettiyseniz okuma ve yazma metotlarının başlarında synchronized anahtar kelimesi mevcuttur. Uygulamayı yazarken işlemlerin gecikmesini ve çakışmasını engellemek için Thread kullanmanız faydalı - hatta mecburi de diyebilirim olacaktır. Bu kelime ise aynı alan üzerinde aynı anda sadece bir iş parçacığının işlem yapmasını sağlar. Evet gördüğünüz gibi gayet kısa. Açıkcası ben bu kadar kısa bir kodlama ile karşılaşacağımı ilk uygulama yazımımda tahmin etmiyordum. Demekki herşey göründüğü gibi değilmiş. Umarım bu yazı faydalı olmuştur. Yeni yazılarda buluşmak üzere. Bol Java' lı günler dileğiyle...