跨平台socket移植实例-libghttp

windows与linux平台使用的socket均继承自Berkeley socket(rfc3493),他们都支持select I/O模型,均支持使用getaddrinfo与getnameinfo实现协议无关编程。但存在细微差别,主要有:

  1. 头文件及类库。windows使用winsock2.h(需要在windows.h前包含),并要链接库ws2_32.lib;linux使用netinet/in.h, netdb.h等。
  2. windows下在使用socket之前与之后要分别使用WSAStartup与WSAClean。
  3. 关闭socket,windows使用closesocket,linux使用close。
  4. send*与recv*函数参数之socket长度的类型,windows为int,linux为socklen_t,可预编译指令中处理这一差异,当平台为windows时#define socklen_t unsigned int。
  5. select函数第一个参数,windows忽略该参数,linux下该参数表示集合中socket的上限值,一般设为sockfd(需select的socket) + 1。
  6. windows下socket函数返回值类型为SOCKET(unsigned int),其中发生错误时返回INVALID_SOCKET(0),linux下socket函数返回值类型int, 发生错误时返回-1。
  7. linux下使用write发送数据,read接收数据,,但是windows不一样,使用send替换掉write,send多一个参数,填个0即可,读取数据时把read替换成recv,最后一个参数填0;

另外,如果绑定本机回环地址,windows下sendto函数可以通过,linux下sendto回报错:errno=22, Invalid arguement。一般情况下均绑定通配地址。

移植实例:

把linux下面的一个http client库libghttp移植到了windows系统下。
实例源码下载:

http://download.csdn.net/detail/earbao/7857789

上面的链接失效了。

重新上传到百度云:http://pan.baidu.com/s/1pJFSByz

#define strcasecmp strcmp

1、修改和添加http_trans.h头部

#ifndef HTTP_TRANS_H
#define HTTP_TRANS_H

#define PLATFORM_WINDOWS  1
#define PLATFORM_MAC      2
#define PLATFORM_UNIX     3
#if defined(_WIN32)
#define PLATFORM PLATFORM_WINDOWS
#elif defined(__APPLE__)
#define PLATFORM PLATFORM_MAC
#else
#define PLATFORM PLATFORM_UNIX
#endif// 接下来我们来把头文件给加进来。   
#if PLATFORM == PLATFORM_WINDOWS
#include <winsock2.h>
#pragma comment( lib, "wsock32.lib" )
#define socklen_t unsigned int

#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
2、http_trans.c

/*
 * http_trans.c -- Functions for doing transport related stuff including
 * automatically extending buffers and whatnot.
 * Created: Christopher Blizzard <[email protected]>, 5-Aug-1998
 *
 * Copyright (C) 1998 Free Software Foundation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#if defined(_WIN32)
#else
  #include <sys/time.h>
#endif
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "http_trans.h"
#include "http_global.h"

static int
http_trans_buf_free(http_trans_conn *a_conn);

int
http_trans_connect(http_trans_conn *a_conn)
{

#if PLATFORM == PLATFORM_WINDOWS
	WSADATA WsaData;
	WSAStartup( MAKEWORD(2,2), &WsaData);
#endif


  if ((a_conn == NULL) || (a_conn->host == NULL))
    goto ec;
  if (a_conn->hostinfo == NULL)
    {
      /* look up the name of the proxy if it's there. */
      if (a_conn->proxy_host)
	{
	  if ((a_conn->hostinfo = gethostbyname(a_conn->proxy_host)) == NULL)
	    {
	      a_conn->error_type = http_trans_err_type_host;
	      a_conn->error = h_errno;
	      goto ec;
	    }
	}
      else
	{
	  /* look up the name */
	  if ((a_conn->hostinfo = gethostbyname(a_conn->host)) == NULL)
	    {
	      a_conn->error_type = http_trans_err_type_host;
	      a_conn->error = h_errno;
	      goto ec;
	    }
	}
      /* set up the saddr */
      a_conn->saddr.sin_family = AF_INET;
      /* set the proxy port */
      if (a_conn->proxy_host)
	a_conn->saddr.sin_port = htons(a_conn->proxy_port);
      else
	a_conn->saddr.sin_port = htons(a_conn->port);
      /* copy the name info */
      memcpy(&a_conn->saddr.sin_addr.s_addr,
	     a_conn->hostinfo->h_addr_list[0],
	     sizeof(unsigned long));
    }
#ifdef _WIN32
  if ((a_conn->sock = socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET)
  {
	  a_conn->error_type = http_trans_err_type_errno;
	  a_conn->error = errno;
	  goto ec;
  }
#else
  /* set up the socket */
  if ((a_conn->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
      a_conn->error_type = http_trans_err_type_errno;
      a_conn->error = errno;
      goto ec;
    }

#endif
   /* set up the socket */
  if (connect(a_conn->sock,
	      (struct sockaddr *)&a_conn->saddr,
	      sizeof(struct sockaddr)) < 0)
    {
      a_conn->error_type = http_trans_err_type_errno;
      a_conn->error = errno;
      goto ec;
    }
  
  return 0;
 ec:
  return -1;
}

http_trans_conn *
http_trans_conn_new(void)
{
  http_trans_conn *l_return = NULL;

  /* allocate a new connection struct */
  l_return = (http_trans_conn *)malloc(sizeof(http_trans_conn));
  memset(l_return, 0, sizeof(http_trans_conn));
  /* default to 80 */
  l_return->port = 80;
  /* default to 1000 bytes at a time */
  l_return->io_buf_chunksize = 1024;
  /* allocate a new trans buffer */
  l_return->io_buf = malloc(l_return->io_buf_chunksize);
  memset(l_return->io_buf, 0, l_return->io_buf_chunksize);
  l_return->io_buf_len = l_return->io_buf_chunksize;
  /* make sure the socket looks like it's closed */
  l_return->sock = -1;
  return l_return;
}

void
http_trans_conn_destroy(http_trans_conn *a_conn)
{
  /* destroy the connection structure. */
  if (a_conn == NULL)
    return;
  if (a_conn->io_buf)
    free(a_conn->io_buf);
  if (a_conn->sock != -1)
    close(a_conn->sock);
  free(a_conn);

#if PLATFORM == PLATFORM_WINDOWS
  closesocket(a_conn->sock);
  WSACleanup();
#endif

  return;
}

const char *
http_trans_get_host_error(int a_herror)
{
  switch (a_herror)
    {
    case HOST_NOT_FOUND:
      return "Host not found";
    case NO_ADDRESS:
      return "An address is not associated with that host";
    case NO_RECOVERY:
      return "An unrecoverable name server error occured";
    case TRY_AGAIN:
      return "A temporary error occurred on an authoritative name server.  Please try again later.";
    default:
      return "No error or error not known.";
    }
}

int
http_trans_append_data_to_buf(http_trans_conn *a_conn,
			      char *a_data,
			      int   a_data_len)
{
  if (http_trans_buf_free(a_conn) < a_data_len)
    {
      a_conn->io_buf = realloc(a_conn->io_buf, a_conn->io_buf_len + a_data_len);
      a_conn->io_buf_len += a_data_len;
    }
  memcpy(&a_conn->io_buf[a_conn->io_buf_alloc], a_data, a_data_len);
  a_conn->io_buf_alloc += a_data_len;
  return 1;
}

int
http_trans_read_into_buf(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;

#ifdef _WIN32
  /* read in some data */
  if ((a_conn->last_read = l_read = recv(a_conn->sock,
	  &a_conn->io_buf[a_conn->io_buf_alloc],
	  l_bytes_to_read,0)) < 0)
  {
	  if (errno == EINTR)
		  l_read = 0;
	  else
		  return HTTP_TRANS_ERR;
  }
#else
  /* read in some data */
  if ((a_conn->last_read = l_read = read(a_conn->sock,
					 &a_conn->io_buf[a_conn->io_buf_alloc],
					 l_bytes_to_read)) < 0)
    {
      if (errno == EINTR)
	l_read = 0;
      else
	return HTTP_TRANS_ERR;
    }

#endif
  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_trans_write_buf(http_trans_conn *a_conn)
{
  int l_written = 0;

  if (a_conn->io_buf_io_left == 0)
    {
      a_conn->io_buf_io_left = a_conn->io_buf_alloc;
      a_conn->io_buf_io_done = 0;
    }
#ifdef  _WIN32
  /* write out some data */
  if ((a_conn->last_read = l_written = send (a_conn->sock,
	  &a_conn->io_buf[a_conn->io_buf_io_done],
	  a_conn->io_buf_io_left,0)) <= 0)
  {
	  if (errno == EINTR)
		  l_written = 0;
	  else
		  return HTTP_TRANS_ERR;
  }
#else
  /* write out some data */
  if ((a_conn->last_read = l_written = write (a_conn->sock,
	  &a_conn->io_buf[a_conn->io_buf_io_done],
	  a_conn->io_buf_io_left)) <= 0)
  {
	  if (errno == EINTR)
		  l_written = 0;
	  else
		  return HTTP_TRANS_ERR;
  }
#endif

  if (l_written == 0)
    return HTTP_TRANS_DONE;
  /* advance the counters */
  a_conn->io_buf_io_left -= l_written;
  a_conn->io_buf_io_done += l_written;
  if (a_conn->io_buf_io_left == 0)
    return HTTP_TRANS_DONE;
  return HTTP_TRANS_NOT_DONE;
}

void
http_trans_buf_reset(http_trans_conn *a_conn)
{
  if (a_conn->io_buf)
    free(a_conn->io_buf);
  a_conn->io_buf = malloc(a_conn->io_buf_chunksize);
  memset(a_conn->io_buf, 0, a_conn->io_buf_chunksize);
  a_conn->io_buf_len = a_conn->io_buf_chunksize;
  a_conn->io_buf_alloc = 0;
  a_conn->io_buf_io_done = 0;
  a_conn->io_buf_io_left = 0;
}

void
http_trans_buf_clip(http_trans_conn *a_conn, char *a_clip_to)
{
  int l_bytes = 0;
  
  /* get the number of bytes to clip off of the front */
  l_bytes = a_clip_to - a_conn->io_buf;
  if (l_bytes > 0)
    {
      memmove(a_conn->io_buf, a_clip_to, a_conn->io_buf_alloc - l_bytes);
      a_conn->io_buf_alloc -= l_bytes;
    }
  a_conn->io_buf_io_done = 0;
  a_conn->io_buf_io_left = 0;
}

char *
http_trans_buf_has_patt(char *a_buf, int a_len,
			char *a_pat, int a_patlen)
{
  int i = 0;
  for ( ; i <= ( a_len - a_patlen ); i++ )
    {
      if (a_buf[i] == a_pat[0])
	{
	  if (memcmp(&a_buf[i], a_pat, a_patlen) == 0)
	    return &a_buf[i];
	}
    }
  return NULL;
}

/* static functions */

static int
http_trans_buf_free(http_trans_conn *a_conn)
{
  return (a_conn->io_buf_len - a_conn->io_buf_alloc);
}


#include "ghttp/ghttp.h"
#include <stdio.h>
#include <stdlib.h>
//异步请求实例
void test001()
{
	char *uri = "http://www.hao123.com";  
	ghttp_request *request = NULL;  
	ghttp_status status;  
	char *buf;  
	int bytes_read;  
	request = ghttp_request_new();  
	if(ghttp_set_uri(request, uri) == -1)  
		exit(-1);  
	if(ghttp_set_type(request, ghttp_type_get) == -1)  
		exit(-1);  
	/* NOTE: Set async request */  
	ghttp_set_sync(request, ghttp_async);  
	ghttp_prepare(request);  

	while(1) {  
		status = ghttp_process(request);  
		if(status == ghttp_error)  
			break;  
		/* NOTE: buf may NULL, notice it */  
		buf = ghttp_get_body(request);  

		
		bytes_read = ghttp_get_body_len(request);  
		printf("%d\n %s\n",bytes_read,buf);
		if(status == ghttp_done) {  
			/* NOTE: Ok, done */  
			break;  
		}  
	}  
	ghttp_clean(request);
	ghttp_request_destroy(request);
	system("pause");
}
//同步请求实例
int test002()
{
	char *uri = "http://www.hao123.com";
	ghttp_request *request = NULL;
	ghttp_status status;
	char *buf;
	int bytes_read;
	request = ghttp_request_new();
	if(ghttp_set_uri(request, uri) == -1)
		return (-1);
	if(ghttp_set_type(request, ghttp_type_get) == -1)
		return(-1);
	ghttp_prepare(request);
	status = ghttp_process(request);
	if(status == ghttp_error)
		return(-1);
	/* OK, done */
	printf("Status code -> %d\n", ghttp_status_code(request));
	buf = ghttp_get_body(request);
	printf("%s\n",buf);
	bytes_read = ghttp_get_body_len(request);
	ghttp_clean(request);
	ghttp_request_destroy(request);
	system("pause");
	return 0;
}
int main(int argc, char *argv[])
{
	//test002();
	test001();
	return 0;
}



你可能感兴趣的:(跨平台socket移植实例-libghttp)