blog.sketchit.de Glaubt mir ich hab den Weihnachtsmann mit eigenen Augen gesehen…

19Okt/092

Kleiner Chat in C (Socketprogrammierung mit UDP)

Hier mal ein kleines Beispiel, wie man per select() und dem UDP Protokoll sehr einfach einen Chat unter C erstellen kann.
Das Programm schaut zuerst, ob auf dem Port 5000 schon jemand lauscht, wenn nicht, wird der 5000er zum senden und der 5001 zum empfangen verwendet. Ist schon ein Chat aktiv, werden die Ports einfach umgedreht.

Der Rest ist normalerweise selbstklärend. Den Chat einfach im Terminal (unter OS X) starten, dann noch ein Terminal Fenster auf machen, auch hier den Chat starten, und schon funktionierts!
Hint:
- kompilieren per "g++ -o test main.c"
- aufruf per "./chat"
- (natürlich ohne die " " )

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>

#include <sys/unistd.h>
#include <sys/fcntl.h>

#include <iostream>

using namespace std;

void reportError(string str) {
	cout << endl << str << errno << endl;
}

int main(int argc, char* argv[])
{
	// set the variables
	int sock, bytes_recieved, bytes_send;
	int port1 = atoi("5000");
	int port2 = atoi("5001");
	char send_data [1024] , recv_data[1024];       

	struct sockaddr_in myAddr;
	struct sockaddr_in clientAddr;
	socklen_t sin_size;

	fd_set rfds;

	// create the tcp socket
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		reportError("Cannot create send socket ....");
		exit(1);
	}

	myAddr.sin_family = AF_INET;
	myAddr.sin_port = htons(port1);
	myAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	if (bind(sock, (struct sockaddr *)&myAddr, sizeof(struct sockaddr))== -1) {
		myAddr.sin_family = AF_INET;
		myAddr.sin_port = htons(port2);
		myAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

		clientAddr.sin_family = AF_INET;
		clientAddr.sin_port = htons(port1);
		clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

		if(bind(sock, (struct sockaddr *)&myAddr, sizeof(struct sockaddr))== -1) {
			reportError("Unable to bind socket.");
			exit(1);
		}
	}
	else
	{
		clientAddr.sin_family = AF_INET;
		clientAddr.sin_port = htons(port2);
		clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	}

	cout << "Wait for data, or type something!" << endl;

	// process incoming connections (forever) ....
	while(1){
		sin_size = sizeof(struct sockaddr_in);

		FD_ZERO(&rfds);
		FD_SET(sock, &rfds);
		FD_SET(0, &rfds);

		select(sock + 1, &rfds, NULL, NULL, NULL);

		if(FD_ISSET(sock, &rfds))
		{
			// receive the reply from the client
			bytes_recieved = recvfrom(sock, recv_data, 1024,0, (struct sockaddr*)&myAddr, &sin_size);

			// client wants the leave, so do we
			if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0) {
				close(sock);
				break;
			}
			else if(bytes_recieved == -1)
			{
				reportError("recvfrom failed.");
				exit(1);
			} else {
				recv_data[bytes_recieved] = '\0';
				cout << "<Received> " << recv_data << endl;
			}
		}
		else if(FD_ISSET(0, &rfds))
		{
			gets(send_data);

			if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0) {
				bytes_send = sendto(sock, send_data, 1024, 0, (struct sockaddr*)&clientAddr, sizeof(struct sockaddr));

				if(bytes_send == -1)
				{
					reportError("Error sending data.");
					exit(1);
				}
			}
			else
			{
				close(sock);
				break;
			}
		}
	}

	close(sock);

	return 0;
}

Hoffe jemanden bringts was!