이번엔 HTTP를 통해 통신을 해보자.
도메인을 입력하면 적절한 메시지로 변환하여 서버에 쏴주고 그 대답을 듣는 내용이다.
추후엔 읽어들일때 buf length를 인식해 종말점을 계산해주는 기능을 추가하려 한다.
배운점
1. character pointer를 문자열로 바꾸는법
char *ip_char = "172.16.3.80";
char ip[IP_LEN];
for(int i = 0; i < 16; i++) {
ip[i] = ip_char[i];
}
2. 구조체를 포인터로 수정하는법
int a;
int *b = &a;
*b = 10
struct addr c;
struct addr *d = &c;
c.ip
d->ip
구조체는 . 으로 접근해서 수정.
하지만 포인터는 . 으로 접근할수 없어서 만든것이 ->
전체 소스코드
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#define PORT_LEN 8
#define IP_LEN 32
#define MSG_MAX 6
#define BUF_LEN 6
#define URL_LEN 128
#define PORT 80
int main(void){
char cmd_str[4];
short cmd;
char tmp;
int r;
int opt = 1;
char port[PORT_LEN];
char ip[IP_LEN];
char URL[URL_LEN];
char proto[IP_LEN];
char path[IP_LEN];
char **path_ptr = path;
char domain[URL_LEN];
int flag = 0;
int flag_str = 0;
char *ip_char;
struct hostent *he;
struct in_addr **addr_list;
struct in_addr addr;
memset(proto, 0, IP_LEN);
memset(ip, 0, IP_LEN);
memset(path, 0, IP_LEN);
memset(URL, 0, IP_LEN);
fputs("원하는 기능을 선택하세요(1 : 서버대기 2 : 클라이언트) : ", stdout);
fgets(cmd_str, 4, stdin);
cmd = cmd_str[0];
if (cmd == '1'){
int server_sock;
struct sockaddr_in sockaddr;
int client_sock;
struct sockaddr_in client_addr;
int socklen, recv_len = BUF_LEN;
int is_first;
char buf[BUF_LEN] = {0,};
char ch;
fputs("포트를 입력하세요 : ", stdout);
fgets(port, sizeof(port) , stdin);
port[strlen(port)-1] = '\0';
printf("포트넘버 %s로 통신합니다\n", port);
/*create server socket*/
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, (socklen_t)sizeof(opt)) < 0) printf("socket set opt failed");
/*set server socket address*/
memset(&sockaddr, 0, sizeof(struct sockaddr_in));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons((unsigned short int)atoi(port));
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("socket address\n");
/* bind */
r = bind(server_sock, (struct sockaddr *)&sockaddr, sizeof(struct sockaddr_in));
if (r < 0) { printf("bind failed Error code: %d\n", errno); return -1;}
printf("bind\n");
/* listen */
r = listen(server_sock, 5);
if (r < 0) { printf("listen failed\n"); }
printf("listen\n");
{
/* accept */
memset(&client_addr, 0, sizeof(struct sockaddr_in));
client_sock = accept(server_sock, (struct sockaddr *)&client_addr, (socklen_t *)&socklen);
if (client_sock < 0) { printf("S accept failed\n"); return -1; }
printf("S accept\n");
while (1) {
is_first = 1;
ch = 0;
while (ch != '\n') {
memset(buf, 0, BUF_LEN);
recv_len = recv(client_sock, buf, BUF_LEN, 0);
if (recv_len < 0) { printf("client close\n"); break; }
ch = buf[recv_len - 1];
buf[recv_len - 1] = 0;
if (is_first) { printf("msg : "); is_first = 0; }
printf("%s%c", buf, ch == '\n' ? '\n' : ch);
}
}
}
close(server_sock);
}
else if (cmd == '2'){
int client_sock;
struct sockaddr_in client_addr;
char buf[512];
int recv_len;
char msg[MSG_MAX];
char message[512], response[4096];
int bytes, sent, received, total;
int send_len, bufrecv_len;
char buf_recv[512];
memset(buf_recv, 0, 512);
memset(msg, 0, MSG_MAX);
memset(message, 0, 512);
while (1){
fputs("도메인을 입력하세요 : ", stdout);
fgets(domain, sizeof(domain) , stdin);
if (domain[0] == 'h') {
strncpy(URL, domain, URL_LEN);
for (int i = 0; i < strlen(URL); i++){
if (URL[i] == ':') flag++;
if (flag == 0) proto[i] = URL[i];
if (flag == 1) break;
}
for (int i = strlen(proto); i < strlen(URL); i++){
if (flag == 3) {
ip[flag_str] = URL[i];
flag_str++;
}
if (URL[i] == '/') flag++;
if (flag == 4) break;
}
flag_str = 0;
for (int i = strlen(proto) + strlen(ip) + 2; i < strlen(URL); i++){
path[flag_str] = URL[i];
flag_str++;
}
path[strlen(path)-1] = '\0';
printf("프로토콜은 %s, 도메인은 %s, path는 %s 입니다. \n", proto, ip, path);
memset(domain, 0, strlen(domain));
strncpy(domain, ip, strlen(ip));
}
port[strlen(port)-1] = '\0';
domain[strlen(domain)-1] = '\0';
if (domain[0] == 'w') {
strncpy(URL, domain, URL_LEN);
for (int i = 0; i < strlen(URL); i++){
if (URL[i] == '/') flag++;
if (flag == 0) ip[i] = URL[i];
if (flag == 1) break;
}
for (int i = strlen(ip); i < strlen(URL); i++){
path[flag_str] = URL[i];
flag_str++;
}
printf("도메인은 %s, path는 %s 입니다. \n", ip, path);
memset(domain, 0, strlen(domain));
strncpy(domain, ip, strlen(ip));
}
if((he = gethostbyname(domain)) == NULL) {
fprintf(stderr, "%s는 등록되지 않은 서버명입니다.\n", domain);
return -1;
}
printf("포트넘버 %s", port);
he = gethostbyname(domain);
printf("ip 주소 타입은 %d ", he->h_length);
printf("공식명칭은 %s ", he->h_name);
ip_char = inet_ntoa(*(struct in_addr*)he->h_addr);
for(int i = 0; i < 16; i++){
ip[i] = ip_char[i];
}
printf("IP주소는 %s입니다\n", ip);
{
/* client socket */
client_sock = socket(AF_INET, SOCK_STREAM, 0);
opt = 1;
setsockopt(client_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (client_sock < 0) { printf("C socket failed\n"); return -1;}
printf("C socket\n");
/* client_sockaddr */
memset(&client_addr, 0, sizeof(struct sockaddr_in));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(PORT);
inet_pton(AF_INET, ip, &client_addr.sin_addr.s_addr);
printf("C socket address\n");
/* connect */
r = connect(client_sock, (struct sockaddr *)&client_addr, sizeof(struct sockaddr_in));
if (r < 0) { printf("C connect failed errno : %d\n", errno); return -1; }
printf("C connect\n");
/*rearrange message */
if (strlen(path) == 0){
path_ptr[0] = 0x2F;
}
char *msg1 = "GET \0";
char *msg2 = " HTTP/1.1\nHOST: \0";
char *msg3 = "\nUser-Agent: curl/7.68.0\nAccept: */*\n\n\0";
char str1[strlen(msg1)+1], str2[strlen(msg2)+1], str3[strlen(msg3)+1];
memset(str1, 0, strlen(msg1)+1);
memset(str2, 0, strlen(msg2)+1);
memset(str3, 0, strlen(msg3)+1);
for (int j = 0; j < strlen(msg1); j++){
str1[j] = msg1[j];
}
for (int j = 0; j < strlen(msg2); j++){
str2[j] = msg2[j];
}
for (int j = 0; j < strlen(msg3); j++){
str3[j] = msg3[j];
}
memcpy(message, str1, strlen(str1));
memcpy(message+strlen(str1), path, strlen(path));
memcpy(message+strlen(str1)+strlen(path), str2, strlen(str2));
memcpy(message+strlen(str1)+strlen(path)+strlen(str2), domain, strlen(domain));
memcpy(message+strlen(str1)+strlen(path)+strlen(str2)+strlen(domain), str3, strlen(str3));
printf("<<request msg>>\n%s", message);
/* request/response */
send_len = send(client_sock, message, strlen(message), 0);
if (send_len < 1) printf("C send failed\n");
printf("<<response msg>>\n");
while(1) {
recv_len = recv(client_sock, buf_recv, 512, 0);
if (recv_len < 1) {
printf("C recv ended\n");
break;
}
printf("%s", buf_recv);
}
close(client_sock);
}
}
} else printf("1, 2만 입력하세요");
return 0;
}
'개발 > C' 카테고리의 다른 글
[C] 포인터란, & * 차이 (0) | 2023.01.10 |
---|---|
[C] 웹소켓프로그래밍 함수 정리 (socket.io) (0) | 2023.01.05 |
[C] 문자열 포인터 (0) | 2022.12.29 |
[C] 구조체 포인터 (0) | 2022.12.29 |
[C] buffer memory flush 하는법 (fgets) (0) | 2022.12.26 |