windows及linux下,socket创建

#include <stdio.h>
#include <string.h>

#ifdef _WIN32

#include <WinSock2.h>

#pragma commnet(lib, "ws2_32.lib");

#else

#include <sys/socket.h>
#include <sys/inet.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/un.h>

#endif

/*==========================================================================================
* 特殊地址区别:
* 	0.0.0.0:表示所有不清楚的主机和目的网络,代表本机所有的IP
*	127.0.0.1:本机地址,在windows系统中,也叫“Localhost”,做测试用
*	255.255.255.255:限制广播地址,不能被路由器转发
*   
*	0.0.0.0指的bai是本地机器上的所有网卡。du比如有三zhi个网卡,如果用
* 0.0.0.0绑定dao80,则三个网版卡都能监听80端口,权而127.0.0.1仅用于虚拟
* 网卡,不会绑定到实际的任意物理网卡。0.0.0.0:80绑定可以从本地和远程进行服务
* 而127.0.0.1:80从其他计算机上是无法访问到本地服务器的。
*
* 使用:
* 	作为服务端:创建套接字时,0.0.0.0(宏定义为INADDR_ANY)
*   作为客户端:连接服务端时,127.0.0.1(本机进程间通信)
*-------------------------------------------------------------------------------------------
* socket参数:
* socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
*
*	family	地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。
*			(AF_UNIX 域实际上是使用本地 socket 文件来通信)
*
*	对应的宏定义:
*		#define AF_INET  2 	(Internet IP Protocol )
*		#define AF_UNIX  1 	(Unix domain sockets )
*       #define AF_INET6 10 (IP version 6)
*		
*	type	套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。
*			SOCK_STREAM是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,
*				多用于资料传送。 
*			SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。
*
*	proto	协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。
*
*	fileno	如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。
*			与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。
*			这可能有助于使用socket.close()关闭一个独立的插座。
*-------------------------------------------------------------------------------------------
* 地址族:AF_INET 和AF_UNIX
*	1 建立socket传递的地址域,及bind()的地址结构稍有区别:
*	  socket() 分别传递不同的域AF_INET和AF_UNIX
*	  bind()的地址结构分别为sockaddr_in(指定IP端口)和sockaddr_un(指定路径名)
*
*	2 AF_INET需经过多个协议层的编解码,消耗系统cpu,并且数据传输需要经过网卡,
*		受到网卡带宽的限制。AF_UNIX数据到达内核缓冲区后,由内核根据指定路径名找到接收方
*		socket对应的内核缓冲区,直接将数据拷贝过去,不经过协议层编解码,节省系统cpu,
*		并且不经过网卡,因此不受网卡带宽的限制。
*
*	3 AF_UNIX的传输速率远远大于AF_INET
*
*	4 AF_INET不仅可以用作本机的跨进程通信,同样的可以用于不同机器之间的通信,其就是为了在
*		不同机器之间进行网络互联传递数据而生。典型的本地IPC,AF_UNIX类似于管道,依赖路径
*		名标识发送方和接收方则只能用于本机内进程之间的通信
*
*-------------------------------------------------------------------------------------------
* TCP 和 UDP 
*	创建:
*		TCP: type = SOCK_STREAM
*		UDP: type = SOCK_DGRAM
*   数据收发:
*   	TCP:recv、send
*		UDP:recvfrom、sendto
*
*-------------------------------------------------------------------------------------------
* setsockopt:用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,
*             但本函数仅定义了最高的“套接口”层次上的选项。
*  使用:
*  1、 在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步);
*      系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中如果发送或是接收的
*      数据量比较大,可以设置socket缓冲区,避免send(),recv()不断的循环收发。
* 
*    int nRecvBufLen = 32 * 1024; //设置为32K
*    setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBufLen, sizeof(int));
*
*  参考:https://baike.baidu.com/item/setsockopt/10069288?fr=aladdin#4
*
*
============================================================================================*/
int set_socket_fcntl(SOCKET fd)
{
#ifdef _WIN32
	u_long optval = 1;
	if (SOCKET_ERROR == ioctlsocket(fd, FIONBIO, &optval)){
		return 1;
	}
	return 0;
#else
	int flag = O_NONBLOCK;
	int flags = fcntl(fd, F_GETFL, 0);
	return fcntl(fd, F_SETFL, O_NONBLOCK | flags);
#endif
}

// windows 客户端:tcp
static SOCKET crete_window_client_tcp_sock(char *ip, int port)
{
	SOCKET sockfd = INVALID_SOCKET;
	int optval = 1;

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == sockfd){
		goto ERROR_CODE;
	}
	// 端口重用
	if (SOCKET_ERROR == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(int)))
	{
		closesocket(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ip);
	addr.sin_port = htons(port);

	// 设置非阻塞模式
	set_socket_fcntl(sockfd);

	if (SOCKET_ERROR == connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) &&
		WSAEWOULDBLOCK != WSAGetLastError() && WSAEINPROGRESS != WSAGetLastError())
	{
		closesocket(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	return sockfd;

ERROR_CODE:
	printf("occur error, code:%d, [%s]!\n", errno, strerror(errno));
	return -1;
}

// windows 服务端:tcp
static SOCKET crete_window_server_tcp_sock(int port)
{
	SOCKET sockfd = INVALID_SOCKET;
	int optval = 1;

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == sockfd){
		goto ERROR_CODE;
	}

	if (SOCKET_ERROR == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(int)))
	{
		closesocket(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(INADDR_ANY);
	addr.sin_port = htons(port);

	// 设置非阻塞模式
	set_socket_fcntl(sockfd);

	if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)))
	{
		closesocket(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	
	if (SOCKET_ERROR == listen(sockfd, 5))
	{
		closesocket(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	return sockfd;

ERROR_CODE:
	printf("occur error, code:%d, [%s]!\n", errno, strerror(errno));
	return -1;
}

/*==================================================================================
UNIX域套接字用于在同一台机器上运行的进程之间的通信。虽然因特网域套接字可用于同一目的,
但UNIX域套接字的效率更高。UNIX域套接字仅仅复制数据;它们并不执行协议处理,不需要添加
或删除网络报头,无需计算检验和,不要产生顺序号,无需发送确认报文
==============================================================================*/
// linux UNIX域 服务端:tcp
static SOCKET cretae_linux_server_udp_sock(char *file_path)
{
	SOCKET sockfd;
	struct sockaddr_un sun;
	bzero(&sun, sizeof(struct sockaddr_un));
	
	if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
		goto ERROR_CODE:
	}
	
	sun.sun_family = AF_UNIX;
	snprintf(sun.sun_path, sizeof(sun.sun_path)-1, "%s", file_path);
	
	int addrLen = sizeof(sun.sun_family) + strlen(sun.sun_path);
	
	if(bind(sockfd, (struct sockaddr*)&sun, addrLen))
	{
		close(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	
	set_socket_fcntl(sockfd);
	
	if(listen(sockfd, 5))
	{
		close(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	
	return sock;
	
ERROR_CODE:
	printf("error code:%d, %s!\n", errno, strerror(errno));
	return -1;
	
}

// linux UNIX域 客户端:tcp
static SOCKET cretae_linux_client_udp_sock(char *file_path)
{
	SOCKET sockfd;
	int len;
	struct sockaddr_un address;
	
	if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
	{
		goto ERROR_CODE;
	}
	
	address.sun_family = AF_UNIX;
	snprintf(address.sun_path, sizeof(address.sun_path)-1, "%s", file_path);
	len = sizeof(address.sun_family)+strlen(address.sun_path);
		
	if(connect(sockfd, (struct sockaddr*)&address, len) == -1 &&
		EWOULDBLOCK != GetLaseError() && EINPROGRESS != GetLaseError())
	{
		close(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}

	set_socket_fcntl(sockfd);
	
	return sockfd;
	
ERROR_CODE:
	printf("error occur, code:%d, %s", errno, strerror(errno));
	return -1;
}

// linux IP family 服务端:tcp
static SOCKET cretae_linux_server_tcp_sock(int port)
{
	SOCKET sockfd;
	int flags;
	struct sockaddr_in addr;
	
	if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
		goto ERROR_CODE;
	
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;
	bzero(&(addr.sin_zero), 8);
	
	if(bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1)
	{
		close(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	
	set_socket_fcntl(sockfd);
	
	if(listen(sockfd, 5))
	{
		close(sockfd);
		sockfd = -1;
		goto ERROR_CODE;
	}
	
	return sockfd;
ERROR_CODE:
	printf("error occur:%d, %s", errno, strerror(errno));
	return -1;
}

// linux IP family 客户端:tcp
static SOCKET cretae_linux_client_tcp_sock(char *ser_ip, int port)
{
	SOCKET sockfd;
	struct sockaddr_in addr = {0};
	
	if((sockfd = socket(PF_INET, SOCK_STREAM, 0))<0)
		goto ERROR_CODE;
	
	// 设置端口重用
	if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
		goto ERROR_CODE;
	
	set_socket_fcntl(sockfd);
	
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ser_ip);
	addr.sin_port = htons(port);
	
	if (-1 == connect(sockfd, (struct sockaddr*)&addr, sizeof(addr))
		&& EWOULDBLOCK!= GetLastError && EINPROGRESS != GetLastError)
	{
		close(sockfd);.
		sockfd = -1;
		goto ERROR_CODE;
	}
	
	return sockfd;
ERROR_CODE:
	printf("error occur, code:%d, %s", errno, strerror("errno"));
	return -1;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值