Dama oyunu sunucu ve istemci olmak üzere iki bileşenden oluşmaktadır. Sunucu kısmını ilk olarak TCP/IP Socket Programlama – Dama Oyunu – Dama Server (1/2)adresinden inceleyebilirsiniz.

Bu yazıda Dama oyununun istemci programı anlatılacaktır.

Dama client:

İstemci programı, ilk önce server a bağlanıp kullanıcı listesini aldıktan sonra, bir yandan server dan yine mesaj beklemeye devam ederken bir yandan da başka bir istemciden bağlantı(oyun oynama isteği veya oyun başlamışsa oyun hamleleri ile ilgili haberleşmeler) beklemelidir.

Yani bir istemci programımız hem sunucu ile hem de başka bir istemci ile (hatta birden fazla istemci ile) aynı anda haberleşmelidir. Başka bir istemci ile haberleşirken bu yazının ilk bölümünde anlatılan sunucu yapısının bir benzerini kullanacaktır. Yani bu durumda istemci, diğer bir istemciye (kullanıcıya) karşı sunucu gibi davranacaktır.

Koda bakalım nasıl yapmışız:

public class client extends Thread {

	private String serverIP;
	private int port;
	private String userName;
	private String rivalName;
	private Message rivalInfo;
	private boolean run = true;

	ObjectInputStream ois;
	ObjectOutputStream oos;

	private ServerSocket clsSocket;
	private Socket socket;

	public static ClientGUI clientGUI;

	public client(String serverIP, int port, String userName) {
		this.serverIP = serverIP;
		this.port = port;
		this.userName = userName;

		clientGUI = new ClientGUI(client.this, client.this.userName);		
	}

	public void startClient() {	
		connectToServer();

		try {
			while(run) {		
					Message message = (Message) ois.readObject();				
					handleMessage(message);
			}
		} catch (SocketException e) {
			clientGUI.showMessage("Server : " + e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				System.out.println(userName + " terminating");
				ois.close();
				oos.close();
				socket.close();
				System.exit(0);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}		
	}

	@Override
	public void run() {

		try {
			clsSocket = new ServerSocket(0);
		} catch (IOException e) {
			e.printStackTrace();
		}

		while (true) {
			try {
				Socket socket = clsSocket.accept();
				if (socket != null) {
					//System.out.println(userName + "kabul ettim basliyorum: " );
					new ClientThread(this, socket, userName, rivalName);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}		
	}

	private void handleMessage(Message message) {

		switch (message.getType()) {

		case Message.USERS_LIST:
			clientGUI.updateUserList(message.getUserList());
			break;

		case Message.BYE:
			run = false;
			clientGUI.showMessage("Server : BYE");
			break;

		case Message.USER_INFO:
			this.rivalInfo = message;
			break;

		case Message.REQUEST_MATCH: { // rival

			int response = JOptionPane.showConfirmDialog(null,
					message.getUserName()
							+ ": want to play match?", "Match Request",
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

			if(response == JOptionPane.YES_OPTION) { // send accept to requester
				this.rivalName = message.getUserName();
				message.setType(Message.START_MATCH);				
				sendToServer(message);
			}
			else {

			}
		};break;

		case Message.START_MATCH:
			new ClientThread(this, this.rivalInfo);
			break;		

		default:
			break;
		}	
	}

	private void connectToServer() { // connect to server

		try {
			this.socket = new Socket(InetAddress.getByName(serverIP), this.port);

			oos = new ObjectOutputStream(socket.getOutputStream());
			oos.flush();
			ois = new ObjectInputStream(socket.getInputStream());

			ois.readObject();		
			Message connectMessage = new Message(Message.CLIENT_CONNECT);
			connectMessage.setUserName(userName);
			//System.out.println(InetAddress.getLocalHost().getHostAddress().toString() + ":" + clsSocket.getLocalPort());
			connectMessage.setMessage(InetAddress.getLocalHost().getHostAddress().toString() + ":" + clsSocket.getLocalPort());
			sendToServer(connectMessage); // send connect info to server

		} catch (UnknownHostException e) {
			clientGUI.showMessage("Unable to connect server\n" + e.getMessage());
			System.exit(0);		
		} catch (IOException e) {
			clientGUI.showMessage("Unable to connect server\n" + e.getMessage());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}		
	}

	public void makeRequest(Message message) {

		this.rivalName = message.getRivalName();
		// get rival info (addr and port)
		sendToServer(message);	
	}

	public void disconnectFromServer() { // disconnect procedure

		sendToServer(new Message(Message.CLIENT_DISCONNECT, userName));	
	}

	public void sendToServer(Message message) {		
		try {
			oos.writeObject(message);
			oos.flush();		
		} catch (IOException e) {		
			clientGUI.showMessage("IO Error:\n" + e.getMessage());
		}
	}

	public static void main(final String[] args) {

		client client = null;
		try {
			client = new client(args[0], Integer.parseInt(args[1]) , args[2]);
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("missing parameter!");
		}
		client.start();
		client.startClient();
	}

}

main methoduna bakarsak; 3 program parametresi (sunucu adresi, sunucu portu, kullanıcı adı) ile client nesnesini yaratıyorum. Ardından start() ile clientin threadini (yani client içindeki run() methodunu) ve sonra da startClient() methodunu çağırıyorum. Bu iki method çalışma esnasında paralel olarak işletilecektir.

startClient() : Sunucu ile iletişimi sağlayan kesimler içermektedir.

thread olarak çalışan run() : Başka bir istemciden bağlantı bekleyen, geldiğinde de yeni bir thread (clientThread) yaratarak istemciler arası oyun haberleşmesini sağlayacak kesimler içermektedir.
Bu sayede birden fazla kullanıcı ile aynı anda oyun oynanabilmektedir.

Diğer sınıfların ne işe yaradığına bakalım;

ClientGUI sınıfı :
client programı ilk çalıştırıldığında kullanıcı arayüzü olarak yaratılır. Kullanıcı listesini gösterir.

clientThread sınıfı :
Az önce anlatıldığı gibi iki istemci arasında oyun başladığında bu istemciler için clientThread ler yaratılıyor. Bu şekilde istemciler artık sadece kendi aralarında haberleşiyorlar. Oyun oynama esnasında sunucu ile hiçbir iletişim olmuyor.

GameGUI sınıfı :
GameGUI sınıfı oyun tablasının oluşturulduğu ve kullanıcının artık görsel olarak dama taşlarını sürükleyip bırakarak oyun oynayabilmesini sağlayan sınıftır. clientThread sınıfı içinde bir nesnesi yaratılır ve istemciler arası iletişime göre dama taşlarının hareketi sağlanır.

client Programının çalıştırılması:

client programı 3 parametre alıyor:
java client sunucu-adresi sunucu-port-no kullanıcı-adı

Örnek: client 127.0.0.1 4461 Hayalet

kullanıcı listesi, Start Match ile istek gönderilir
oyun isteğinin onaylanması
oyunun başlaması (aynı makine üzerinde)
Programlarda olağan dışı hareketler (disconnect e basmadan çıkma, dama oyun kurallarının bazıları, arayüzün bazen yeniden çizilememesi vb..) denetlenmemiştir ve bu tip sorunlar ve istisnalar ortaya çıkabilir. Bu örnek Socket Programlama odaklı olduğundan bu yönüyle incelenmelidir.

4 Comments

  • Merhaba kardeş sorunumun basitçe özeti gerçek sunucuya nasıl bağlanabilirim ?

    cliend ile sunucudaki açık portlara bağlanıyor fakat sunucuda oluşturduğum porta uzaktan bağlanamıyorum ?

    1. Merhaba,
      Çok geniş bir soru. Nasıl bir sunucuda, nasıl bir ağ ve güvenlik yapılandırmasında, hangi işletim sisteminde, client makinenin bu ağdaki konumuna göre birçok sebebi olabilir.
      En basit firewall olabilir iki makine arasında.

ss için bir yanıt yazın Yanıtı iptal et

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.