Оооо ами забавно. UDP-базиран чат сървър ще е голяма занимавка според мен, нямаш формално установяване и затваряне на сесия, прекалено много неща ще трябва да мислиш, а от гледна точка на сигурност и стабилност нещата придобиват грозен характер.
За да ползваш udp протокола, трябва да имаш идея за следните неща:
1) кога една комуникация се счита за "установена" - т.е предполагам не искаш за всеки идиот, който ти пусне един UDP scan да речем, да асоцираш разни структури и да заделяш обем памет (в C). Това ще ти трябва и при положение че пазиш някаква таблица с "клиенти", навързани към сървъра
2) Кога една комуникация се прекратява. Може да си дефинираш някаква команда в твоя чат протокол, но какво става ако отсрещната страна затвори клиента, преди да я изпрати, вечно ли ще стои в таблицата от клиенти, или след даден timeout период ще се счита за "разкачена"? Ако има такъв timeout, дали няма да има вариант да "разкачаш" клиенти, които просто не пращат продължително време нищо, без да са затворили клиента?
3) По какъв начин ще различаваш клиентите си, ако имаш 10 клиента зад НАТ примерно (трябва ти да си следиш и source port)
4) Колко е ефективна такава комуникация, нямаш гаранция, че отсреща нещото ще се получи или не, трябва да имплементираш някакъв механизъм, който да осигурява потвърждения на приетите данни. Накрая като нищо можеш да завършиш, преоткривайки топлата вода (т.е TCP протокола
'> )
Иначе при tcp-базираните "server" sockets има няколко варианта какво да правиш след socket()/bind()/listen()/цикълът с accept():
1) За всеки нов сокет, fork()-ваш нов процес, който комуникира само с този сокет, който е върнат от accept(). Това е модела в ранните apache-ta, както и все още на доста приложения (postgresql например). Според мен това е най-тъпия вариант: представи си 100 едновременни клиента, за които вдигаш нови процеси, имаш много кофти context switch-ове, load average, който ако не е 100, то ще е поне 10-20-30, разхищение на памет, тъпотия.
2) За всеки нов сокет, вдигаш една нишка с pthread_create(). Този вариант е доста по-бърз от първия, защото нишките споделят обща памет и ресурси и почти няма копиране на данни в паметта между нишките, но въпреки това, един такъв сървър пак няма да може да понася големи натоварвания. Въпреки това, този метод е изключително разпространен.
3) Обработваш всички accept()-нати сокети в рамките на един процес/нишка. Това се постига с разни polling механизми, като има поне 2 варианта - poll()/select() и epoll-базиран. select() е бавна работа, обхожда се в ядрото един масив за всеки сокет и вади лоша производителност при голям брой клиенти. epoll нещата обаче са доста бързи, по-бързи от всичко останало (в това число прехваления kqueue на FreeBSD). Има и някакви варианти с RT сигнали, но не ги знам.
Проблемът там е че това нещо не е скалируемо - ако имаш няколко процесора, твоят сървър може да се изпълнява само върху един процесор в един определен момент, така че и 8-процесорна машина да си вземеш, няма да има почти никаква разлика с еднопроцесорна. Отделно, трябва да се пише много внимателно, защото една грешка ще съсипе цялото приложение, не определен процес или нишка.
4) Смесен вариант - до неотдавна имах манията да си пиша HTTP load-balancer, като реших да ползвам някаква бройка workthreads със собствени epoll sets. Като идея е прекрасно, би трябвало това да е най-добрата софтуерна архитектура, обаче поради некадърни locking механизми, това моето нещо когато го докарах до работен вариант, не можеше да държи повече от 100-200 едновременни конекции (apache backend-ите, сами по себе си държаха повече, хаха). Това е най-добрият вариант, но очевидно трябва да се пишат нещата вече наистина много внимателно - освен проблемите присъщи на еднонишковите event-based модели (epoll), това придобива и проблемите на многонишковите приложения, там конкурентност, мутекси, глупости. Ако си добър програмист, това вероятно е най-добрият вариант, но аз явно далеч не съм такъв
'>
И сега като финал, замисли се за сигурността на един UDP сървър: нямаш sequence numbers, а подправянето на udp пакети е изключително лесно. С hping3 примерно можеш лесно да правиш UDP floods със случайни подправени източници и съдържание на пакетите. Замисли се докъде може да доведе това нещо твоето приложение
'>
П.П. търси в гугъл за "c10k" в момента в който направиш нещо работещо и искаш да го изпипаш и оптимизираш като хората
'>