C语言socket HTTP Server hello world程序(Ubuntu Linux 24.04环境)

本程序实现的是一个能返回hello world的http server, 也只能返回hello world,作为C语言http server开发的一个起步阶段。

/*
编译生成可执行程序(Ubuntu Linux 24.04)
# gcc ./socket_server.c -o socket_server
# scp socket_server root@idealand.space:/root/code/buda/c
启动http server
# ./socket_server http_single_thread
启动client message display
# ./socket_server show_client_messages

查看防火墙的状态:(国内的云服务器80,443,8080,8443是备案端口,必须备案以后才能从外网访问,注意避免使用)
# ufw status
# ufw allow 8888
查看端口是否被其它程序占用
# sudo apt lsof
# lsof -i:8888
*/

#include <stdio.h>      // printf
#include <string.h>	    // strlen(char*)
#include <unistd.h>     // close(int file_descriptor): close socket
#include <sys/socket.h> // socket(), bind(), accept(), etc
#include <netdb.h>      // gethostbyname(char* domain_name)
#include <arpa/inet.h>	// long inet_addr(char* ip_address) : convert ip string to long int format

#define SERVER_LISTEN_PORT 8888
#define SOCK_BUF_SIZE 10241
#define SOCK_BUF_SIZE1 10240 // subtract 1 for the null terminator at the buf end
#define SOCK_CONN_QUEUE_MAX 3
#define MODE_show_client_messages "show_client_messages"
#define MODE_http_single_thread "http_single_thread"
#define HTTP_HEAD "HTTP/1.1 200 OK\n\
Server: buda\n\
Content-Type: text/html\n\
Content-Length: %ld\n\
\n\
%s"

enum MODE
{
  SHOW_CLIENT_MESSAGES=1, HTTP_SINGLE_THREAD
};

typedef int (*FUN_process_connection_sock)(int sock, char* buffer, int buf_size); 

int make_http_response(char* buf, int buf_size)
{
	char* content="<!DOCTYPE html><body>hello world</body></html>";
  int len=sprintf(buf, HTTP_HEAD, strlen(content) , content); buf[len]=0;
	return len;
}


// server waits for messages from client, and display messages in server console
// the listen socket and connection sockets work in the same single thread, so the queued clients may be blocked for a very long time.
int show_client_messages_single_thread(int sock, char* buffer, int buf_size)
{
	long recv_size=0, buf_size1=buf_size-1;
  while((recv_size = recv(sock, buffer, buf_size1, 0))>0)
	{
		if(recv_size<0) { printf("receive from client failed\n"); return -1;}
		buffer[recv_size]=0; // set string end
		printf("received %ld bytes data: \n%s\n", recv_size, buffer);
	}
}

// server waits for a message from client, response it, and close the connection, then wait for the next client to connect
// the listen socket and connection sockets work in the same single thread
int http_single_thread(int sock, char* buffer, int buf_size)
{
	int r=0;
	long recv_size=0, buf_size1=buf_size-1;
  recv_size = recv(sock, buffer, buf_size1, 0);
	
	if(recv_size<0) { printf("receive from client failed\n"); return -1;}
	buffer[recv_size]=0; // set string end
	printf("received %ld bytes data: \n%s\n", recv_size, buffer);

  int send_size = make_http_response(buffer, buf_size);
	r = send(sock, buffer, send_size, 0);
	if(r>0) printf("[sent to client]\n%s\n[end of sent]\n", buffer);
	return r;
}

int main(int argc, char * argv[])
{
	int r=0; enum MODE mode=SHOW_CLIENT_MESSAGES; 
	FUN_process_connection_sock fun_sock=show_client_messages_single_thread;

	if(argc>=2)
	{
		if(strcmp(MODE_http_single_thread, argv[1])==0) 
		{ mode=HTTP_SINGLE_THREAD; fun_sock=http_single_thread; printf("server work in http_single_thread mode\n"); }
	}
	if(mode==SHOW_CLIENT_MESSAGES) printf("server work in client_messages_single_thread mode\n");

	int listen_sock, sock;
	struct sockaddr_in server_addr, client_addr;
	socklen_t addrlen = sizeof(struct sockaddr_in);

  int client_count=0;	char *client_ip; int client_port;

	char buffer[SOCK_BUF_SIZE] = { 0 };
	long send_size=0;

	if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create server listen socket failed\n"); goto fail; 	}
	printf("create server listen socket succeed\n");

	server_addr.sin_family = AF_INET; // IPv4
	server_addr.sin_addr.s_addr = INADDR_ANY;	// 监听所有本地IP地址
	server_addr.sin_port = htons(SERVER_LISTEN_PORT);
	if (bind(listen_sock, (struct sockaddr*)&server_addr, addrlen) == -1) { perror("server listen socket bind to ip:port failed\n"); goto fail_close; }
	printf("bind server listen socket to port %d succeed\n", SERVER_LISTEN_PORT);

	if (listen(listen_sock, SOCK_CONN_QUEUE_MAX) == -1) { perror("server socket start listening failed\n"); goto fail_close; }
	printf("server socket starts listening ...\n");

	while((sock	= accept(listen_sock, (struct sockaddr*)&client_addr,	&addrlen)) > 0)
	{			
		client_count++;
		client_ip = inet_ntoa(client_addr.sin_addr); client_port = ntohs(client_addr.sin_port);
		printf("%d --------------- \nserver socket accepted a client connection:  %s:%d ---------------\n", client_count, client_ip, client_port);
		// if(set_socket_options(sock) == -1) goto end_close_client;
    if(fun_sock(sock, buffer, SOCK_BUF_SIZE) < 0) goto end_close_client;
		end_close_client: close(sock);
		printf("waiting for next client ...\n");
	}

	close(listen_sock); goto succeed;
	fail_close: close(listen_sock); goto fail;
	succeed: return r;
	fail: r=1; return r;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuzen

您的资助将帮助我创作更好的作品

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值