Консольный чат на С/ Ncurses
Недавно решил сделать мини-консольный чат на С + Ncurses, который представляет из себя TCP-server и TCP-client. Если не использовать ncurses сам чат рабоает без проблем, только иногда появляются лишние пробелы на стороне клиента (на удаленном сервере тоже работает). Пробелма заключается в том, что при добавлении ncures функционала, функция get_message программы работает как-то не так. Вроде бы я пробовал записывать что-то в файл, чтобы проверить запускается ли она вообще, так вот она запускается. Не работает именно вывод в чат и именно при получении сообщения от сервера.
TCP-сервер
#include <stdbool.h>
#include <unistd.h>
#include <pthread.h>
#include "../../Utils/Utils.h"
#include "../../Utils/Help.h"
struct AcceptedSocket
{
int acceptedSocketFD;
struct sockaddr_in address;
int error;
bool acceptedSuccessfully;
};
struct AcceptedSocket * acceptIncomingConnection(int serverSocketFD);
void acceptNewConnectionAndReceiveAndPrintItsData(int serverSocketFD);
void receiveAndPrintIncomingData(int socketFD);
void startAcceptingIncomingConnections(int serverSocketFD);
void receiveAndPrintIncomingDataOnSeparateThread(struct AcceptedSocket *pSocket);
void sendReceivedMessageToTheOtherClients(char *buffer,int socketFD);
struct AcceptedSocket acceptedSockets[10] ;
int acceptedSocketsCount = 0;
void startAcceptingIncomingConnections(int serverSocketFD) {
while(true)
{
struct AcceptedSocket* clientSocket = acceptIncomingConnection(serverSocketFD);
acceptedSockets[acceptedSocketsCount++] = *clientSocket;
receiveAndPrintIncomingDataOnSeparateThread(clientSocket);
}
}
void receiveAndPrintIncomingDataOnSeparateThread(struct AcceptedSocket *pSocket) {
pthread_t id;
pthread_create(&id,NULL,receiveAndPrintIncomingData,pSocket->acceptedSocketFD);
}
void receiveAndPrintIncomingData(int socketFD) {
char buffer[1024];
while (true)
{
ssize_t amountReceived = recv(socketFD,buffer,1024,0);
if(amountReceived>0)
{
buffer[amountReceived] = 0;
printf("%s\n",buffer);
sendReceivedMessageToTheOtherClients(buffer,socketFD);
}
if(amountReceived==0)
break;
}
close(socketFD);
}
void sendReceivedMessageToTheOtherClients(char *buffer,int socketFD) {
for(int i = 0 ; i<acceptedSocketsCount ; i++)
if(acceptedSockets[i].acceptedSocketFD !=socketFD)
{
send(acceptedSockets[i].acceptedSocketFD,buffer, strlen(buffer),0);
}
}
struct AcceptedSocket * acceptIncomingConnection(int serverSocketFD) {
struct sockaddr_in clientAddress ;
int clientAddressSize = sizeof (struct sockaddr_in);
int clientSocketFD = accept(serverSocketFD,&clientAddress,&clientAddressSize);
struct AcceptedSocket* acceptedSocket = malloc(sizeof (struct AcceptedSocket));
acceptedSocket->address = clientAddress;
acceptedSocket->acceptedSocketFD = clientSocketFD;
acceptedSocket->acceptedSuccessfully = clientSocketFD>0;
if(!acceptedSocket->acceptedSuccessfully)
acceptedSocket->error = clientSocketFD;
return acceptedSocket;
}
int main() {
int serverSocketFD = createTCPIpv4Socket();
char ip[MAX_IPv4_LENGTH];
int port;
get_connection_address(ip, &port);
struct sockaddr_in *serverAddress = createIPv4Address(ip, port);
int result = bind(serverSocketFD,serverAddress, sizeof(*serverAddress));
if(result == 0)
printf("socket was bound successfully\n");
int listenResult = listen(serverSocketFD,10);
startAcceptingIncomingConnections(serverSocketFD);
shutdown(serverSocketFD,SHUT_RDWR);
return 0;
}
TCP-клиент
#include <stdbool.h>
#include <unistd.h>
#include <pthread.h>
#include "../../Utils/Utils.h"
#include "../../Utils/Help.h"
#include "../../Graphics/ChatBox.h"
void make_client(int fd);
void* get_message(void* socketPT);
void send_messages(int socketFD, char* name);
int main() {
char ip[MAX_IPv4_LENGTH];
int port;
get_connection_address(ip, &port);
int socketFD = createTCPIpv4Socket();
struct sockaddr_in *address = createIPv4Address(ip, port);
int result = connect(socketFD, (struct sockaddr*)address, sizeof (*address));
if(result == 0)
printf("connection was successful\n");
char name[MAX_NAME_LENGTH];
get_name(name);
make_client(socketFD);
init_interface();
send_messages(socketFD, name);
close_chat();
close(socketFD);
return 0;
}
void send_messages(int socketFD, char* name) {
#if 0
char *line = NULL;
size_t lineSize= 0;
printf("type and we will send(type exit to leave the chat)...\n");
char buffer[1024];
#endif
char buffer[1024];
int length = 0;
while(true)
{
memset(buffer, 0, sizeof(buffer));
length = 0;
#if 0
line = NULL;
ssize_t charCount = getline(&line,&lineSize,stdin);
line[charCount-1]=0;
sprintf(buffer,"%s:%s",name , line);
if(charCount>0)
{
if(strcmp(line,"exit")==0)
break;
ssize_t amountWasSent = send(socketFD,
buffer,
strlen(buffer), 0);
}
#endif
int status = read_input(buffer, &length);
if(status != 1 )
{
printf("\n");
break;
}
buffer[length]= '\0';
if (length > 0){
char* self_string = calloc(sizeof(char), length + 10);
strcat(self_string, "You: ");
strcat(self_string, buffer);
add_message(self_string);
free(self_string);
char* send_string = calloc(sizeof(char), length + 10);
strcat(send_string, name);
strcat(send_string, ": ");
strcat(send_string, buffer);
ssize_t amountWasSent = send(socketFD,
send_string,
strlen(send_string), 0);
free(send_string);
}
}
}
void make_client(int socketFD)
{
pthread_t id ;
pthread_create(&id, NULL, get_message, (void*)&socketFD);
}
void* get_message(void* socketPT) {
int socketFD = *(int*)socketPT;
char buffer[1024];
while (true)
{
ssize_t amountReceived = recv(socketFD, buffer, 1024, 0);
add_message(buffer);
if(amountReceived>0)
{
buffer[amountReceived] = 0;
add_message(buffer);
// printf("%s\n ",buffer);
}
if(amountReceived==0)
break;
}
close(socketFD);
}
файл интерфейса чата
#include <ncurses.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#define MSG_CNT 16
#define MSG_LENGTH 256
static WINDOW* info_win;
static WINDOW* msg_win;
static WINDOW* input_win;
char messages[MSG_CNT][MSG_LENGTH];
static void init_info()
{
info_win = newwin(5, 65, 0, 10);
box(info_win, 0, 0);
wrefresh(info_win);
}
static void init_msg()
{
msg_win = newwin(20, 65, 5, 10);
box(msg_win, 0 ,0);
wrefresh(msg_win);
}
static void init_input()
{
input_win = newwin(4 ,65 ,25 ,10);
box(input_win , 0 ,0);
wmove(input_win , 1 ,1);
wrefresh(input_win);
}
void init_interface()
{
setlocale(LC_ALL, "");
initscr();
cbreak();
noecho();
init_info();
init_msg();
init_input();
keypad(input_win ,TRUE);
}
void update_message()
{
wclear(msg_win);
box(msg_win ,0 ,0);
for (int i=0; i<MSG_CNT; i++)
{
mvwprintw(msg_win ,i+1 ,1 ,"%s", messages[i]);
}
wrefresh(msg_win );
wmove(input_win , 1 ,1);
wrefresh(input_win);
}
void add_message(const char* msg)
{
for (int i=1; i<MSG_CNT; i++)
{
memcpy(messages[i-1], messages[i], MSG_LENGTH);
}
strncpy(messages[MSG_CNT -1], msg ,MSG_LENGTH -1 );
messages[MSG_CNT -1][MSG_LENGTH -1] = '\0';
update_message();
}
int read_input(char *buffer ,int *size)
{
int symbol;
while ((symbol=wgetch(input_win)) != ERR)
{
if (symbol == '\n')
{
if (strncmp(buffer, "/exit", 5) == 0){
return 2;
}
mvwprintw(input_win ,1 ,1 ,"%*s" ,*size ,"");
wrefresh(input_win );
return 1;
}
else if (symbol == KEY_BACKSPACE || symbol ==127)
{
if (*size >0)
{
(*size)--;
mvwprintw(input_win ,1 ,*size +1 ," ");
wmove(input_win ,1 ,*size +1 );
wrefresh(input_win );
buffer[*size] = '\0';
}
}
else if (*size < MSG_LENGTH -1)
{
buffer[*size] = (char)symbol;
(*size)++;
mvwaddch(input_win ,1 ,*size ,"");
mvwaddch(input_win ,1 ,*size ,symbol );
wrefresh(input_win );
}
}
return 0;
}
void close_chat()
{
endwin();
}
Его заголовочный файл
#ifndef CHAT_BOX_H
#define CHAT_BOX_H
void init_interface();
void update_message();
void add_message(const char* msg);
int read_input(char *buffer ,int *size);
void close_chat();
#endif
За остальные файлы я ручаюсь, потому что с ними все работало очень долго. Да и там нет никаких функций влияющих на отправку или получение данных с консоли или чат-интерфейса.
Спасибо за внимание