当前位置: 首页 > 工具软件 > libghttp > 使用案例 >

libghttp仅一个连接的服务端测试

包和泰
2023-12-01

接收带有  "Connection: close\r\n"  将会发送ok失败

libghttp用gethostbyname()解析域名 线程不安全。 可改用 getaddrinfo 

libhttp 文件多 代码短,涉及功能更多  里面的test等样例不是最新 要改造 https://www.libhttp.org/  

--makefile

 

CC:=gcc 
MAKE:=make
CFLAGS:=-O -g -Wall
BIN=../bin/
LIB=../lib/
SRC=../src/
RM:= rm -f
HIDE=@
##
libghttp_la_FNAMES=ghttp \
	http_date \
	http_hdrs \
	http_req \
	http_resp \
	http_trans \
	http_base64 \
	http_uri 
include_HEADERS = ghttp.h ghttp_constants.h
libghttp_la_OBJECTS= ghttp.o http_date.o http_hdrs.o http_req.o http_resp.o http_trans.o http_base64.o http_uri.o 
EXTRA_DIST += \
	http_date.h \
	http_global.h \
	http_hdrs.h \
	http_req.h \
	http_resp.h \
	http_trans.h \
	http_uri.h \
	http_base64.h 
##
ALLFN=mmsS  $(libghttp_la_FNAMES)  
ALLOBJ=mmsS.o $(libghttp_la_OBJECTS)
##################dynamic  static
LDFLAGS=  -lpthread -lrt  -L../lib/   
CPPFLAGS:= -I.   -I../src/
##../lib/name.o
pOBJCB= $(foreach aobj,$(ALLOBJ),../lib/$(aobj))
###########链接规则
$(BIN)mms:$(pOBJCB)
	$(CC) $(CFLAGS) $(pOBJCB)  $(LDFLAGS)  $(CPPFLAGS)  -o   $@
###########自动生成编译规则########################
##../lib/name.o:../src/name.call
##		$(CC) -c  $(CFLAGS) $(CPPFLAGS)  $^  -o  $@
###################################################
define  Function_prec
$2:$1
	$$(CC) -c  $$(CFLAGS) $$(CPPFLAGS)  $$^  -o  $$@
endef	
$(foreach one,$(ALLFN),\
$(eval $(call Function_prec,../src/$(one).c,../lib/$(one).o))\
)
###########清空
clear:
	$(RM)  $(LIB)*.o
	$(RM)  $(BIN)mms


 

 

--mmsS.c

 

 

 

#include<time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include "ghttp.h"
#include "http_uri.h"
#include "http_hdrs.h"
#include "http_trans.h"
#include "http_req.h"
#include "http_resp.h"
#include "http_date.h"
#include "http_global.h"
#include "http_base64.h"
#define  DEBUG_PRINTF
#define  http_resq_read_body(a,b,c)   http_resp_read_body(a,b,c)
typedef  http_resp  mmsSreq;
struct _ghttp_request
{
	http_uri           *uri;
	http_uri           *proxy;
	http_req           *req;
	http_resp          *resp;
	http_trans_conn    *conn;
	const char         *errstr;
	int                 connected;
	ghttp_proc          proc;
	char               *username;
	char               *password;
	char               *authtoken;
	char               *proxy_username;
	char               *proxy_password;
	char               *proxy_authtoken;
};
typedef enum header_state_tag
{
	reading_header = 0,
	reading_value,
	reading_sep,
	reading_eol
} header_state;

char *memmem(char *haystack, size_t hlen, char *needle, size_t nlen) {
	if (nlen == 0) return haystack; /* degenerate edge case */
	if (hlen < nlen) return 0; /* another degenerate edge case */
	char *hlimit = haystack + hlen - nlen + 1;
	while (NULL!=(haystack = memchr(haystack, needle[0], hlimit - haystack))) {
		if (!memcmp(haystack, needle, nlen)) return haystack;
		haystack++;
	}
	return 0;
}
int http_trans_accept(http_trans_conn  *conn,int sockServer)
{
	socklen_t  len = sizeof(struct sockaddr);
	//会阻塞进程,直到有客户端连接上来为止
	conn->sock = accept(sockServer, (struct sockaddr*)&(conn->saddr), &len);
	if (conn->sock < 0) 
	{
		printf("accept errno\n");
		return -1;
	}
	printf("get  client\n"); 
	return conn->sock;
}
int http_trans_listen(http_trans_conn  *a_conn,int *psockServer,const int port)
{
	struct sockaddr_in addrServer; 
	(*psockServer) = socket(AF_INET, SOCK_STREAM, 0);
	if (*psockServer == -1) 
	{
		a_conn->error_type = http_trans_err_type_errno;
		a_conn->error = errno;
		return -1;
	}
	addrServer.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY表示任何IP
	addrServer.sin_family = AF_INET;
	addrServer.sin_port = htons(port);//绑定端口

	bind((*psockServer), (struct sockaddr*)&addrServer, sizeof(struct sockaddr));

	//Listen监听端
	listen((*psockServer), 5);//5为等待连接数目
	printf("server:服务器已启动:\n监听中...\n");
	return 1;

}
double XX_httplib_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before) {

	return ((double)(ts_now->tv_nsec - ts_before->tv_nsec)) * 1.0E-9 +
		((double)(ts_now->tv_sec - ts_before->tv_sec));

}  /* XX_httplib_difftimespec */
int XX_httplib_pull(int scfd, char *buf, int len, double timeout)
{
	int  err;
	int nread;
	struct timespec start;
	struct timespec now;
	if (timeout > 0) {
		memset(&start, 0, sizeof(start));
		memset(&now, 0, sizeof(now));
		clock_gettime(CLOCK_MONOTONIC, &start);
	}
	do {
		nread = (int)read(scfd, buf, (size_t)len);
		err = (nread < 0) ? errno : 0;
		if (nread > 0 || (nread == 0 && len == 0))
		{
			return nread;
		}
		if (nread < 0)
		{
			/*
			* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
			* if the timeout is reached and if the socket was set to non-
			* blocking in close_socket_gracefully, so we can not distinguish
			* here. We have to wait for the timeout in both cases for now.
			*/
			if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) {

				/*
				* EAGAIN/EWOULDBLOCK:
				* standard case if called from close_socket_gracefully
				* => should return -1
				* or timeout occured
				* => the code must stay in the while loop
				*
				* EINTR can be generated on a socket with a timeout set even
				* when SA_RESTART is effective for all relevant signals
				* (see signal(7)).
				* => stay in the while loop
				*/
			}
			else return -1;
		}
		if (timeout > 0) clock_gettime(CLOCK_MONOTONIC, &now);
	} while (timeout <= 0 || XX_httplib_difftimespec(&now, &start) <= timeout);
	return nread;
}
static int
http_trans_buf_free(http_trans_conn *a_conn)
{
	return (a_conn->io_buf_len - a_conn->io_buf_alloc);
}
int
http_trans_read_into_buf2(http_trans_conn *a_conn)
{
	int l_read = 0;
	int l_bytes_to_read = 0;

	/* set the length if this is the first time */
	if (a_conn->io_buf_io_left == 0)
	{
		a_conn->io_buf_io_left = a_conn->io_buf_chunksize;
		a_conn->io_buf_io_done = 0;
	}
	/* make sure there's enough space */
	if (http_trans_buf_free(a_conn) < a_conn->io_buf_io_left)
	{
		a_conn->io_buf = realloc(a_conn->io_buf,
			a_conn->io_buf_len + a_conn->io_buf_io_left);
		a_conn->io_buf_len += a_conn->io_buf_io_left;
	}
	/* check to see how much we should try to read */
	if (a_conn->io_buf_io_left > a_conn->io_buf_chunksize)
		l_bytes_to_read = a_conn->io_buf_chunksize;
	else
		l_bytes_to_read = a_conn->io_buf_io_left;
	/* read in some data */
	if((a_conn->last_read = l_read = XX_httplib_pull(a_conn->sock, &a_conn->io_buf[a_conn->io_buf_alloc], l_bytes_to_read, 0.5))
		<0)
	//
	{
		if (errno == EINTR)
			l_read = 0;
		else
			return HTTP_TRANS_ERR;
	}
	else if (l_read == 0)
		return HTTP_TRANS_DONE;
	/* mark the buffer */
	a_conn->io_buf_io_left -= l_read;
	a_conn->io_buf_io_done += l_read;
	a_conn->io_buf_alloc += l_read;
	/* generate the result */
	if (a_conn->io_buf_io_left == 0)
		return HTTP_TRANS_DONE;
	return HTTP_TRANS_NOT_DONE;
}


int
http_resq_read_headers(mmsSreq*a_req, http_trans_conn *a_conn)
{
	char          *l_start_body = NULL;
	int            l_rv = 0;
	int            l_done = 0;
	int            l_return = HTTP_TRANS_DONE;
	char          *l_start_header = NULL;
	int            l_header_len = 0;
	char          *l_last_header = NULL;
	int            l_last_header_len = 0;
	char          *l_start_value = NULL;
	int            l_value_len = 0;
	char          *l_cur_ptr = NULL;
	char          *l_ptr = NULL;
	header_state   l_state = reading_header;

	/* check to see if we need to jump in somewhere */
	if (a_conn->sync == HTTP_TRANS_ASYNC)
	{
		if (a_req->header_state == http_resp_reading_header)
			goto http_req_reading_header_jump;
	}
	/* start reading headers */
	do
	{
		a_req->header_state = http_resp_reading_header;
	http_req_reading_header_jump:
		/* read in the buffer */
		l_rv = http_trans_read_into_buf2(a_conn);
		/* check for an error */
		if (l_rv == HTTP_TRANS_ERR)
		{
			a_conn->errstr = "Failed to read http request line";
			l_return = HTTP_TRANS_ERR;
			goto ec;
		}
		/* check to see if the end of headers string is in the buffer */
		l_start_body = memmem(a_conn->io_buf, a_conn->io_buf_alloc,"\r\n\r\n" , 4);
		if (l_start_body != NULL)
		{	
			l_done = 1;//头結束
			break;
		}
		if ((l_done == 0) && (a_conn->sync == HTTP_TRANS_ASYNC) && (l_rv == HTTP_TRANS_NOT_DONE))
			return HTTP_TRANS_NOT_DONE;
		/* yes, that !l_done is ther because in the case of a 100
		continue we well get back up to this loop without doing a
		successful read. */
		if ((!l_done) && (l_rv == HTTP_TRANS_DONE) && (a_conn->last_read == 0))
		{
			printf("<%s>", a_conn->io_buf);
			a_conn->errstr = "Short read while reading http response headers";
			return HTTP_TRANS_ERR;
		}
	} while (l_done == 0);
	/* parse out the  header 解析头部*/  
#ifdef  DEBUG_PRINTF
	printf("%s", a_conn->io_buf);
#endif
	 //**************
	l_ptr = a_conn->io_buf;
	l_cur_ptr = l_ptr;
	while (*l_cur_ptr != '\r')
		l_cur_ptr++;
	
	/* see if there are any headers.  If there aren't any headers
	then the end of the reason phrase is the same as the start body
	as above.  If that's the case then skip reading any headers. */
	if (l_cur_ptr == l_start_body)
		l_done = 1;
	else
		l_done = 0;
	
	while ((*l_cur_ptr == '\r') ||
		(*l_cur_ptr == '\n'))
		l_cur_ptr++;
	/* start parsing out the headers */
	/* start at the beginning */
	l_start_header = l_cur_ptr;
	
	while (l_done == 0)
	{
		/* check to see if we're at the end of the
		headers as determined above by the _patt() call */
		if (l_cur_ptr == (l_start_body + 1))
			break;
		/* reading the header name */
		if (l_state == reading_header)
		{
			/* check to see if there's leading whitespace.
			If that's the case then it needs to be combined
			from the previous header */
			if (l_header_len == 0)
			{
				if ((*l_cur_ptr == ' ') || (*l_cur_ptr == '\t'))
				{
					/* bomb if it's the first header.  That's not valid */
					if ((l_last_header == NULL) || (l_last_header_len == 0))
					{
						a_conn->errstr = "The first http request header began with whitespace";
						l_return = HTTP_TRANS_ERR;
						goto ec;
					}
					l_cur_ptr++;
					/* set it reading sep.  sep will eat all of the write space */
					l_state = reading_sep;
					continue;
				}
			}
			if (*l_cur_ptr == ':')
			{
				/* make sure that there's some header there */
				if (l_header_len == 0)
				{
					a_conn->errstr = "An http request header was zero length";
					l_return = HTTP_TRANS_ERR;
					goto ec;
				}
				/* start reading the seperator */
				l_state = reading_sep;
				l_cur_ptr++;
			}
			/* make sure there's a seperator in
			there somewhere */
			else if (*l_cur_ptr == '\r')
			{
				a_conn->errstr = "Failed to find seperator in http request headers";
				l_return = HTTP_TRANS_ERR;
				goto ec;
			}
			else
			{
				l_cur_ptr++;
				l_header_len++;
			}
		}
		/* read the seperator */
		else if (l_state == reading_sep)
		{
			/* walk until you get a non-whitespace character */
			if ((*l_cur_ptr == ' ') || (*l_cur_ptr == '\t'))
				l_cur_ptr++;
			else
			{
				l_state = reading_value;
				l_start_value = l_cur_ptr;
				l_value_len = 0;
			}
		}
		/* read the value */
		else if (l_state == reading_value)
		{
			/* check to see if we've reached the end of the
			value */
			if ((*l_cur_ptr == '\r') || (*l_cur_ptr == '\n'))
			{
				/* check to see if this is a continuation of the last
				header. If the header len is 0 and we've gotten to
				this point then that's the case */
				if (l_header_len == 0)
				{
					http_hdr_set_value_no_nts(a_req->headers,
						l_last_header,
						l_last_header_len,
						l_start_value,
						l_value_len);
				}
				else
				{
					http_hdr_set_value_no_nts(a_req->headers,
						l_start_header,
						l_header_len,
						l_start_value,
						l_value_len);

					/* set the last header and the length so that a new line
					that starts with spaces can figure out what header it
					applies to */
					l_last_header = l_start_header;
					l_last_header_len = l_header_len;
				}
				/* start eating the end of line */
				l_state = reading_eol;
			}
			else
			{
				l_cur_ptr++;
				l_value_len++;
			}
		}
		/* read the eof */
		else if (l_state == reading_eol)
		{
			/* eat the eol */
			if ((*l_cur_ptr == '\r') || (*l_cur_ptr == '\n'))
				l_cur_ptr++;
			else
			{
				/* start reading a new header again. */
				l_state = reading_header;
				l_start_header = l_cur_ptr;
				l_header_len = 0;
			}
		}
		/* what state is this? */
		else
		{
			a_conn->errstr = "Unknown state while reading http request headers";
			l_return = HTTP_TRANS_ERR;
			goto ec;
		}
	}
	/* clip the buffer */
	http_trans_buf_clip(a_conn, l_start_body + 4);
ec:
	a_req->header_state = http_resp_header_start;
	return l_return;
}

ghttp_status ServerTrans(ghttp_request*a_request)
{
	int l_rv = 0;
	//****
	//ENTITY HEADERS
	//****
	if (a_request->proc == ghttp_proc_none)
	{
		l_rv = http_resq_read_headers(a_request->resp, a_request->conn);
		if (l_rv == HTTP_TRANS_ERR)
		{
			a_request->errstr = a_request->conn->errstr;
			return ghttp_error;
		}
		if (l_rv == HTTP_TRANS_NOT_DONE)
			return ghttp_not_done;
		if (l_rv == HTTP_TRANS_DONE)
		{
			a_request->proc = ghttp_proc_request;
			if (a_request->conn->sync == HTTP_TRANS_ASYNC)
				return ghttp_not_done;
		}
	}
	//****
	//body
	//****
	if (a_request->proc == ghttp_proc_request)
	{

			l_rv = http_resq_read_body(a_request->resp,
				a_request->req,
				a_request->conn);
			if (l_rv == HTTP_TRANS_ERR)
			{
				/* make sure that the connected flag is fixed and stuff */
				if (a_request->conn->sock == -1)
					a_request->connected = 0;
				return ghttp_error;
			}
			if (l_rv == HTTP_TRANS_NOT_DONE)
				return ghttp_not_done;
			if (l_rv == HTTP_TRANS_DONE)
			{
				/* make sure that the connected flag is fixed and stuff */
				if (a_request->conn->sock == -1)
					a_request->connected = 0;
				a_request->proc = ghttp_proc_none;
				return ghttp_done;
		     }
	//只調用body部分  request 的body  到response  body
	}
	a_request->errstr = a_request->conn->errstr;
	return ghttp_error;
}

int   serverGet(int port)
{ 
char *temresult = NULL;
ghttp_request *request = NULL;
ghttp_status status;
request = ghttp_request_new();//uri目标uri  代理uri 请求  响应  sock连接   malloc  
if (-1 == ghttp_set_sync(request, ghttp_sync))
{
	printf("ghttp_set_sync error\n");
	ghttp_request_destroy(request);
	return -1;
}
int sockServer;
http_trans_listen(request->conn, &sockServer,port);//结束需要close(sockeServer)
if (sockServer < 0)
{
	printf("http_trans_listen error\n");
	ghttp_request_destroy(request);
	return -1;
}
http_trans_accept(request->conn, sockServer);
close(sockServer);//此处监听只收一条,这里就关闭
//--把接收的请求写道resp的结构中  没有写回信息  对方unknow errno
#ifdef  DEBUG_PRINTF
printf("---head---\n");
#endif
status = ServerTrans(request);
if (status == ghttp_error)
{
	printf("trans:%s\n", ghttp_get_error(request));
	ghttp_request_destroy(request);
	return -1;
}
temresult = ghttp_get_body(request);
printf("---body---\n");
printf("%s", temresult);

//==
char senbuf[200] = "HTTP/1.1 200 ok\r\nContent-Type:application/json\r\nContent-Length:9\r\n\r\n{receive}";
write(request->conn->sock,senbuf,strlen(senbuf));
//==

ghttp_request_destroy(request);
return 0;
}
int main(int argc, char*argv[]) 
{

	serverGet(8080);

	return 0;
}

 

 

 

 

 

 

 

 

 

 类似资料: