반응형
기본은 전체 전송하는 메시지
그냥 string을 쳐주고 enter를 치면 전송됨.
패킷은 사이즈에 따라 돈을 내야함. 불필요한 패킷은 없애야함. 프로세스라고 보면 할 일 없을 때 sleep을 해야되는데, 자신의 메시지도 아닌데 interrupt로 깨어나서 처리해야되니, 괜히 깨어난거임. 고로 1대1 메시지 기능이 있음.
[13] ㅇㅇ 이런식으로 보내면 13번에게만 메시지를 보내줌.
[idlist]를 치면 접속되어 있는 클라이언트의 리스트가 쭉 나옴.
여러 client와의 통신연결이 서로 다른 스레드에서 지속적으로 이어져 있고 각각의 동작을 하기 때문에, 전역변수, 전역함수를 mutex로 막아줘야함.
ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ
iot_client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <signal.h>
#define BUF_SIZE 100
#define NAME_SIZE 20
#define ARR_CNT 5
void * send_msg(void * arg);
void * recv_msg(void * arg);
void error_handling(char * msg);
char name[NAME_SIZE]="[Default]";
char msg[BUF_SIZE];
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in serv_addr;
pthread_t snd_thread, rcv_thread;
void * thread_return;
if(argc != 4) {
printf("Usage : %s <IP> <port> <name>\n",argv[0]);
exit(1);
}
sprintf(name, "%s",argv[3]);
sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock == -1)
error_handling("socket() error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect() error");
sprintf(msg,"[%s:PASSWD]",name);
write(sock, msg, strlen(msg));
pthread_create(&rcv_thread, NULL, recv_msg, (void *)&sock);
pthread_create(&snd_thread, NULL, send_msg, (void *)&sock);
pthread_join(snd_thread, &thread_return);
// pthread_join(rcv_thread, &thread_return);
close(sock);
return 0;
}
void * send_msg(void * arg)
{
int *sock = (int *)arg;
int str_len;
int ret;
fd_set initset, newset;
struct timeval tv;
char name_msg[NAME_SIZE + BUF_SIZE+2];
FD_ZERO(&initset);
FD_SET(STDIN_FILENO, &initset);
fputs("Input a message! [ID]msg (Default ID:ALLMSG)\n",stdout);
while(1) {
memset(msg,0,sizeof(msg));
name_msg[0] = '\0';
tv.tv_sec = 1;
tv.tv_usec = 0;
newset = initset;
ret = select(STDIN_FILENO + 1, &newset, NULL, NULL, &tv);
if(FD_ISSET(STDIN_FILENO, &newset))
{
fgets(msg, BUF_SIZE, stdin);
if(!strncmp(msg,"quit\n",5)) {
*sock = -1;
return NULL;
}
else if(msg[0] != '[')
{
strcat(name_msg,"[ALLMSG]");
strcat(name_msg,msg);
}
else
strcpy(name_msg,msg);
if(write(*sock, name_msg, strlen(name_msg))<=0)
{
*sock = -1;
return NULL;
}
}
if(ret == 0)
{
if(*sock == -1)
return NULL;
}
}
}
void * recv_msg(void * arg)
{
int * sock = (int *)arg;
int i;
char *pToken;
char *pArray[ARR_CNT]={0};
char name_msg[NAME_SIZE + BUF_SIZE +1];
int str_len;
while(1) {
memset(name_msg,0x0,sizeof(name_msg));
str_len = read(*sock, name_msg, NAME_SIZE + BUF_SIZE );
if(str_len <= 0)
{
*sock = -1;
return NULL;
}
name_msg[str_len] = 0;
fputs(name_msg, stdout);
/* pToken = strtok(name_msg,"[:]");
i = 0;
while(pToken != NULL)
{
pArray[i] = pToken;
if(i++ >= ARR_CNT)
break;
pToken = strtok(NULL,"[:]");
}
// printf("id:%s, msg:%s,%s,%s,%s\n",pArray[0],pArray[1],pArray[2],pArray[3],pArray[4]);
printf("id:%s, msg:%s\n",pArray[0],pArray[1]);
*/
}
}
void error_handling(char * msg)
{
fputs(msg, stderr);
fputc('\n', stderr);
exit(1);
}
iot_server.c
/* author : KSH */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#define BUF_SIZE 100
#define MAX_CLNT 32
#define ID_SIZE 10
#define ARR_CNT 5
#define DEBUG
typedef struct {
char fd;
char *from;
char *to;
char *msg;
int len;
}MSG_INFO;
typedef struct {
int index;
int fd;
char ip[20];
char id[ID_SIZE];
char pw[ID_SIZE];
}CLIENT_INFO;
void * clnt_connection(void * arg);
void send_msg(MSG_INFO * msg_info, CLIENT_INFO * first_client_info);
void error_handling(char * msg);
void log_file(char * msgstr);
int clnt_cnt=0;
pthread_mutex_t mutx;
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
int clnt_adr_sz;
int sock_option = 1;
pthread_t t_id[MAX_CLNT] = {0};
int str_len = 0;
int i;
char idpasswd[(ID_SIZE*2)+3];
char *pToken;
char *pArray[ARR_CNT]={0};
char msg[BUF_SIZE];
CLIENT_INFO client_info[MAX_CLNT] = {{0,-1,"","1","PASSWD"}, \
{0,-1,"","2","PASSWD"}, {0,-1,"","3","PASSWD"}, \
{0,-1,"","4","PASSWD"}, {0,-1,"","5","PASSWD"}, \
{0,-1,"","6","PASSWD"}, {0,-1,"","7","PASSWD"}, \
{0,-1,"","8","PASSWD"}, {0,-1,"","9","PASSWD"}, \
{0,-1,"","10","PASSWD"}, {0,-1,"","11","PASSWD"}, \
{0,-1,"","12","PASSWD"}, {0,-1,"","13","PASSWD"}, \
{0,-1,"","14","PASSWD"}, {0,-1,"","15","PASSWD"}, \
{0,-1,"","16","PASSWD"}, {0,-1,"","17","PASSWD"}, \
{0,-1,"","18","PASSWD"}, {0,-1,"","19","PASSWD"}, \
{0,-1,"","20","PASSWD"}, {0,-1,"","21","PASSWD"}, \
{0,-1,"","22","PASSWD"}, {0,-1,"","23","PASSWD"}, \
{0,-1,"","24","PASSWD"}, {0,-1,"","25","PASSWD"}, \
{0,-1,"","26","PASSWD"}, {0,-1,"","27","PASSWD"}, \
{0,-1,"","28","PASSWD"}, {0,-1,"","29","PASSWD"}, \
{0,-1,"","30","PASSWD"}, {0,-1,"","31","PASSWD"}, \
{0,-1,"","HM_CON","PASSWD"}};
if(argc != 2) {
printf("Usage : %s <port>\n",argv[0]);
exit(1);
}
fputs("IoT Server Start!!\n",stdout);
if(pthread_mutex_init(&mutx, NULL))
error_handling("mutex init error");
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sock_option, sizeof(sock_option));
if(bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr))==-1)
error_handling("bind() error");
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
while(1) {
clnt_adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &clnt_adr_sz);
if(clnt_cnt >= MAX_CLNT)
{
printf("socket full\n");
shutdown(clnt_sock,SHUT_WR);
continue;
}
else if(clnt_sock < 0)
{
perror("accept()");
continue;
}
str_len = read(clnt_sock, idpasswd, sizeof(idpasswd));
idpasswd[str_len] = '\0';
if(str_len > 0)
{
i=0;
pToken = strtok(idpasswd,"[:]");
while(pToken != NULL)
{
pArray[i] = pToken;
if(i++ >= ARR_CNT)
break;
pToken = strtok(NULL,"[:]");
}
for(i=0;i<MAX_CLNT;i++)
{
if(!strcmp(client_info[i].id,pArray[0]))
{
if(client_info[i].fd != -1)
{
sprintf(msg,"[%s] Already logged!\n",pArray[0]);
write(clnt_sock, msg,strlen(msg));
log_file(msg);
shutdown(clnt_sock,SHUT_WR);
#if 1 //for MCU
client_info[i].fd = -1;
#endif
break;
}
if(!strcmp(client_info[i].pw,pArray[1]))
{
strcpy(client_info[i].ip,inet_ntoa(clnt_adr.sin_addr));
pthread_mutex_lock(&mutx);
client_info[i].index = i;
client_info[i].fd = clnt_sock;
clnt_cnt++;
pthread_mutex_unlock(&mutx);
sprintf(msg,"[%s] New connected! (ip:%s,fd:%d,sockcnt:%d)\n",pArray[0],inet_ntoa(clnt_adr.sin_addr),clnt_sock,clnt_cnt);
log_file(msg);
write(clnt_sock, msg,strlen(msg));
pthread_create(t_id+i, NULL, clnt_connection, (void *)(client_info + i));
pthread_detach(t_id[i]);
break;
}
}
}
if(i == MAX_CLNT)
{
sprintf(msg,"[%s] Authentication Error!\n",pArray[0]);
write(clnt_sock, msg,strlen(msg));
log_file(msg);
shutdown(clnt_sock,SHUT_WR);
}
}
else
shutdown(clnt_sock,SHUT_WR);
}
return 0;
}
void * clnt_connection(void *arg)
{
CLIENT_INFO * client_info = (CLIENT_INFO *)arg;
int str_len = 0;
int index = client_info->index;
char msg[BUF_SIZE];
char to_msg[MAX_CLNT*ID_SIZE+1];
int i=0;
char *pToken;
char *pArray[ARR_CNT]={0};
char strBuff[130]={0};
MSG_INFO msg_info;
CLIENT_INFO * first_client_info;
first_client_info = (CLIENT_INFO *)((void *)client_info - (void *)( sizeof(CLIENT_INFO) * index ));
while(1)
{
memset(msg,0x0,sizeof(msg));
str_len = read(client_info->fd, msg, sizeof(msg)-1);
if(str_len <= 0)
break;
msg[str_len] = '\0';
pToken = strtok(msg,"[:]");
i = 0;
while(pToken != NULL)
{
pArray[i] = pToken;
if(i++ >= ARR_CNT)
break;
pToken = strtok(NULL,"[:]");
}
msg_info.fd = client_info->fd;
msg_info.from = client_info->id;
msg_info.to = pArray[0];
sprintf(to_msg,"[%s]%s",msg_info.from,pArray[1]);
msg_info.msg = to_msg;
msg_info.len = strlen(to_msg);
sprintf(strBuff,"msg : [%s->%s] %s",msg_info.from,msg_info.to,pArray[1]);
log_file(strBuff);
send_msg(&msg_info, first_client_info);
}
close(client_info->fd);
sprintf(strBuff,"Disconnect ID:%s (ip:%s,fd:%d,sockcnt:%d)\n",client_info->id,client_info->ip,client_info->fd,clnt_cnt-1);
log_file(strBuff);
pthread_mutex_lock(&mutx);
clnt_cnt--;
client_info->fd = -1;
pthread_mutex_unlock(&mutx);
return 0;
}
void send_msg(MSG_INFO * msg_info, CLIENT_INFO * first_client_info)
{
int i=0;
if(!strcmp(msg_info->to,"ALLMSG"))
{
for(i=0;i<MAX_CLNT;i++)
if((first_client_info+i)->fd != -1)
write((first_client_info+i)->fd, msg_info->msg, msg_info->len);
}
else if(!strcmp(msg_info->to,"IDLIST"))
{
char* idlist = (char *)malloc(ID_SIZE * MAX_CLNT);
msg_info->msg[strlen(msg_info->msg) - 1] = '\0';
strcpy(idlist,msg_info->msg);
for(i=0;i<MAX_CLNT;i++)
{
if((first_client_info+i)->fd != -1)
{
strcat(idlist,(first_client_info+i)->id);
strcat(idlist," ");
}
}
strcat(idlist,"\n");
write(msg_info->fd, idlist, strlen(idlist));
free(idlist);
}
else
for(i=0;i<MAX_CLNT;i++)
if((first_client_info+i)->fd != -1)
if(!strcmp(msg_info->to,(first_client_info+i)->id))
write((first_client_info+i)->fd, msg_info->msg, msg_info->len);
}
void error_handling(char *msg)
{
fputs(msg, stderr);
fputc('\n', stderr);
exit(1);
}
void log_file(char * msgstr)
{
fputs(msgstr,stdout);
}
Makefile
#CC:=arm-linux-gcc
CC:=gcc
TARGET_SRV=iot_server
OBJECT_SRV=$(TARGET_SRV).o
TARGET_CLN=iot_client
OBJECT_CLN=$(TARGET_CLN).o
#LDFLAGS=-D_REENTRANT -pthread -lmysqlclient
LDFLAGS=-D_REENTRANT -pthread
all : $(TARGET_SRV) $(TARGET_CLN)
$(TARGET_SRV):$(OBJECT_SRV)
$(CC) -o $@ $(OBJECT_SRV) $(LDFLAGS)
$(TARGET_CLN):$(OBJECT_CLN)
$(CC) -o $@ $(OBJECT_CLN) $(LDFLAGS)
%.o:%.c
$(CC) -c -o $@ $<
clean:
rm -f *.o $(TARGET_SRV) $(TARGET_CLN)
같은 폴더에 넣고 make를 치면 자동으로 object file을 만들어줌.
반응형
반응형
'Ubuntu' 카테고리의 다른 글
[Linux] Ubuntu VMware CLI환경으로 동작시키기 (0) | 2024.03.04 |
---|---|
linux 파일 비교 프로그램 meld (0) | 2024.02.22 |
IPC(Inter-Process-Communication) C언어 실습 (0) | 2024.02.19 |
ubuntu와 ubuntu간 nfs 설정 (0) | 2024.02.19 |
[Jetson Nano] 젯슨 나노 OS 이미지 올리기 (1) | 2024.02.16 |