2 Ocak 2018 Salı

C ile UDP Socket Kullanımı

Giriş
Linux'ta şu satırlar dahil edilir.
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
Windows'ta şu satır dahil edilir.
#include <Winsock2.h>
Windows'ta socket kütüphanesini ilklendirmek için şöyle yaparız.
WORD wVersionRequested= MAKEWORD(2, 2);WSADATA wsaData;

int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
  printf("WSAStartup failed with error: %d\n", err);
}
Socket Handle
Winsock API'si SOCKET yapısı ile çalışıyor gibi görünüyor. Ancak altta SOCKET aslında unsigned int. Linux'ta ise socket API'si int ile çalışıyor. Ortak bir yapı için int olarak tutulabilir.
Socket Açmak
Örnek
Winsock ve Linux'ta şöyle yaparız.
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Örnek
Şu kullanım da doğru
int fd = socket(AF_INET,SOCK_DGRAM,0);
Açıklaması şöyle
The only valid values for protocol are 0 and IPPROTO_TCP for TCP sockets, and 0 and IPPROTO_UDP for UDP sockets. For SOCK_RAW you may specify a valid IANA IP protocol defined in RFC 1700 assigned numbers.
Eğer hata varsa <0 döner. Şöyle yaparız.
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  perror("cannot create socket\n");
}
Örnek
Şöyle yaparız.
// Create the socket
SOCKET mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (!mSocket) { 
  printf("Socket failed with error code : %d", WSAGetLastError());
}
bind
Sunucu socketlerde kullanılır.
Örnek
Şöyle yaparız.
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(54164);
local.sin_addr.s_addr = htonl (INADDR_ANY);

bind(fd, (struct sockaddr *) &local, sizeof(local));
Eğer hata varsa < 0 döner. Şöyle yaparız.
if (bind(fd, (struct sockaddr *)local, sizeof(local)) < 0) {
  perror("bind failed");
}
Örnek
Eğer tüm ağ arayüzlerini değil sadece belli bir ağ arayüzünü dinlemek istersek şöyle yaparız.
local.sin_addr.s_addr = inet_addr("127.0.0.1");
Örnek
Adres şöyle de doldurulabilir. bzero veya memzero ile tüm alanları sıfırlarız.
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family =AF_INET;
servaddr.sin_port = htons (54164);
Sebebi ise INADDR_AYN değerinin 0 olması.
# define INADDR_ANY ((unsigned long int) 0x00000000)
Örnek
Şöyle yaparız.
sockaddr_in socketAddr = { 0 };
socketAddr.sin_family = PF_INET;
socketAddr.sin_port = htons(1010);
socketAddr.sin_addr.s_addr = INADDR_ANY;

//Bind
if (bind(socket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) == SOCKET_ERROR) {
  printf("Bind failed with error code : %d", WSAGetLastError());
}
close metodu
Winsock'ta şöyle yaparız.
::closesocket (fd);
Linux'ta şöyle yaparız.
::close (fd);
shutdown metodu
Metodun imzası şöyle
int shutdown (int s, int how); // s is socket descriptor
Windows'ta kullanılan parametreler Linux'tan farklı. Windows'ta şöyle yaparız.
::shutdown (fd, SD_BOTH); //SD_RECEIVE , SD_SEND
Linux'ta şöyle yaparız.
::shutdown (fd, SHUT_RDWR); //SHUT_RD, SHUTWR
getAvailableBytes
Şöyle yaparız.
int bytesAvailable = 0;
ioctl (fd,FIONREAD,&bytesAvailable);
return bytesAvailable;
getLocalPort
Şöyle yaparız.
struct sockaddr_in addr;
int len = sizeof(struct addr);
getsockname(fd, (struct sockaddr *) &addr, &len); return ntohs (addr.sin_port);
getLastError metodu
Windows'ta şöyle yaparız.
return WSAGetLastError();
Linux'ta şöyle yaparız.
return errno;
recvfrom metodu

İlk parametre socket, ikinci parametre verinin okunacağı alan, üçüncü parametre alanın büyüklüğü, dördüncü parametre flags ama hep 0 kullanılır, beşinci parametre veriyi gönderen adres, altıncı parametre adresin büyüklüğüdür.Örnek
Şöyle yaparız

#define BUFLEN      512

struct sockaddr_in claddr;  // address of the client
char buf[BUFLEN];
socklen_t clientlen  = sizeof(claddr);

long recvlen=recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *)&claddr, &clientlen);
Eğer hata yoksa > 0 okunur. Bu durumda karakter okuyorsak şöyle yaparız.
if (recvlen > 0) {
  buf[recvlen] = 0;
}
Örnek
Şöyle yaparız.
// Receive and time
char buffer[50];
sockaddr_in senderAddr;
int senderAddrSize = sizeof(senderAddr);

int transferred = recvfrom(mSocket, (char*)buffer, 50, 0,
  (sockaddr*)&senderAddr, &senderAddrSize);
sendto metodu
İlk parametre socket, ikinci parametre gönderilecek veri, üçüncü parametre verinin büyüklüğü, dördünce parametre flags ama hep 0 kullanılır, beşinci parametre gönderilecek adres, altıncı parametre ise adresin büyüklüğüdür.
Örnek
Şöyle yaparız.
char buf[512];struct sockaddr_in servaddr; // server's address
socklen_t slen = sizeof(servaddr);

sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&servaddr, slen) < 0)
Adres şöyle doldurulur.
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port   = htons(6349);inet_pton (AF_INET,"...",&servaddr.sin_addr);
Eğer socketin gönderme belleğinde yer yoksa hata kodu olarak Linux'ta EMSGSIZE alırız.

setsockopt metodu

SO_RCVBUF
Receive Buffer Size'ı öğrenmek için şöyle yaparız.
int bufSize = 65535;
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(int)
return bufSize;
SO_RCVTIMEO
Bu değer Windows'ta en az 500 ms olmalı. Açıklaması şöyle.
There is an undocumented minimum limit of about 500mS on SO_RCVTIMEO.
Şöyle yaparız.
// Set timeout
DWORD lBuffer[2] = { 0, 0 };
int lSize;
lBuffer[0] = static_cast<DWORD>(1000.0 * timeout);
lSize = sizeof(DWORD);
if (setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)lBuffer, lSize) != 0) {
  printf("Set socket option failed with error code : %d", WSAGetLastError());
}

// Check that we get what we set.
DWORD lBufferout[2] = { 0, 0 };
if (getsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)lBufferout, &lSize) != 0) {
  printf("Get socket option failed with error code : %d", WSAGetLastError());
}
SO_REUSEADDR
Winsock ve Linux'ta şöyle yaparız. Aynı adrese birden fazla socketin bağlanmasına izin verir. Özellikle sunucu socket için bind() yapmadan önce kullanılır.
int enable = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0)

SO_BROADCAST
Winsock ve Linux'ta şöyle yaparız.
int broadcast = 1;
// this call is what allows broadcast packets to be sent:
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof (broadcast));




Hiç yorum yok:

Yorum Gönder