Извини, что долго не отвечал. Не было возможности.
Ты уже разобрался с селектом? Если да, то можешь не читать

.
Я посмотрел твой код.
Что тебе нужно делать:
1. Использовать селект при каждом чтении и записи в сокет
2. Проверять возвращаемое функциями recv и send значение ВСЕГДА.
Селект останавливает выполнение процесса/потока до того момента, когда во входном буфере сокета появятся данные, готовые к употреблению или сокет, в который ты собираешься гнать данные, будет готов их принять. Иначе ты впустую тратишь время процессора на бесполезный цикл чтения/записи. Селект можно использовать не только с сокетами, а в принципе с любыми файловыми дескрипторами (по крайней мере с stdin точно можно, про остальное не уверен).
Я не буду повторять man, укажу только главное.
int select(номер_дескриптора_с_максимальным_значением + 1,/*!!!Не количество дескрипторов!!!*/
набор_дескрипторов_для_чтения,/*0 если читать ничего не надо*/
набор_дескрипторов_для_записи,/*0 если записывать ничего не надо*/
набор_дескрипторов_для_исключений,/*ставь смело в 0*/
время_ожидания)
В примере устанавливается на ожидание только один сокет и только на чтение или только на запись, но ты можешь установить их столько, сколько надо и на оба действия. Например, stdin можешь поставить на чтение, а сокет — на запись. Появились данные в stdin — прочитал, готов сокет — записал.
int socketReady(int s, int rw, int sec, int usec) {//rw = 0 - чтение, rw = 1 - запись
struct timeval tv;
fd_set rfds;
fd_set wfds;
fd_set *cfds;
int res;
FD_ZERO(&rfds); //читай man select
FD_ZERO(&wfds);
tv.tv_sec = sec;
tv.tv_usec = usec;
if(!rw) cfds = &rfds; //ожидаем сокет на чтение
else cfds = &wfds; //ожидаем сокет на запись
FD_SET(s, cfds); //читай man select
//обрати внимание на первый параметр.
//!!!селект сбрасывает значения rfds и wfds, поэтому их надо устанавливать
//перед каждым вызовом селект.
res = select(s + 1, &rfds, &wfds, 0, &tv);
if(res == -1) {
// error
return ERROR;
} else if(!res) {
// socket not ready, timeout expired
return END_TIMEOUT;
}
//проверяем, готов ли нужный сокет
if(FD_ISSET(s, cfds)) //читай man select
return READY;
else return ERROR;
}
и дальше
wile(1) {
if(READY == (result = socketReady(s, 0, 10, 0))) { //читаем
currRead = recv(s, readBuff, readBuffLen, 0);
if(currRead = -1) {
//ошибка, проверяем errno и вываливаемся из цикла или нет
} else if(currRead == 0) {
//тоже ненормально, значит сокет на том конце закрыт, вываливаемся из цикла
} else {
//работаем с тем, что получили,
//количество полученного равно currRead
}
} else {
//проверяем, что вернулось и т. д.
}
}
и запись
wile(1) {
if(READY == (result = socketReady(s, 1, 10, 0))) { //пишем
sent = send(s, writeBuff, len, 0);
if(sent = -1) {
//ошибка, проверяем errno и вываливаемся из цикла или нет
} else if(sent < len) {
//записалось не всё, нужно будет дописывать то, что осталось в буфере
} else {
//готовим следующую порцию или заканчиваем
}
} else {
//проверяем, что вернулось и т. д.
//и вываливаемся из цикла, если надо
}
}
И ещё несколько замечаний.
Нет никакого признака того, что из сокета прочитаны все данные. И то, что прочитано меньше, чем размер буфера, не говорит ни о чём. Нужно самостоятельно как-то уведомлять получателя о количестве отправленных данных или о том, что достигнут конец данных (какая-нибудь волшебная завершающая последовательность).
Если из сокета прочитано 0 байт, это значит то, он закрыт на другом конце, а не то, что в него отправлено 0 байт.
Сокет может быть закрыт на запись и открыт на чтение и наоборот. Смотри man 2 shutdown.
Если время ожидания вышло, это говорит только о том, что в читающем сокете до сих пор ничего нет или из пишущего сокета ничего не отправлено получателю (может он там просто забыл читать из сокета). Здесь надо самому принимать решение, что делать.