Windows网络编程~TCP/IP~socket(二)

1、socket

1、什么是socket

socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket
这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。
个人理解:将底层复杂的协议体系、执行流程进行封装得到的接口,以便于调用协议进行通信。

2、本质

unsigned int 就是一个整数,一种数据类型,标识当前的应用程序,协议等信息。

3、应用:

通过socket作为客户端服务器的唯一身份标识

4、socket函数参数
填0的时候,由系统决定填什么

socket(
    _In_ int af,		//地址的类型 AF_INET  AF_INET6 AF_BTH 
    _In_ int type,     //套接字类型  SOCK_STREAM...
    _In_ int protocol	//协议的类型  IPPROTO。。。
    );

常用套接字类型
<1>流式套接字(SOCK_STREAM)—TCP
提供面向连接的、可靠的传输服务,数据无差错,无重复的发送,
且按发送顺序接收。
<2>数据报式套接字(SOCK_DGRAM)(UDP)
提供无连接服务。不提供无差错保证,数据可能丢失或者重复,并且接收顺序混乱。
<3>原始套接字(SOCK_RAW)(端口扫描工具。。。自己写的包)

	SOCKET socketserver = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if (INVALID_SOCKET == socketserver)
	{
		int a = WSAGetLastError();//获取错误码
		printf("socket创建失败");
		WSACleanup();
	}
	closesocket(socketserver);

2、bind函数

1、作用

为socket绑定端口号与具体地址

2、 参数
WSAAPI

bind(
    _In_ SOCKET s,	//上个函数创建的socket,绑定了协议信息,bind绑定实际的地址以及端口号
    _In_reads_bytes_(namelen) const struct sockaddr FAR * name,//对应的sockaddr_in结构体
    _In_ int namelen  参数2类型的大小
    );

sockaddr_in结构体内容

/*
 * Socket address, internet style.
 */
struct sockaddr_in {
        short   sin_family; //地址族
        u_short sin_port;	//端口号
        struct  in_addr sin_addr;  //IP地址
        char    sin_zero[8];//不使用
};

IP地址结构体原型:

//
// IPv4 Internet address
// This is an 'on-wire' format structure.
//
typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;
#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

返回值

含义
EADDRINUSE给定地址已经使用
EBADFsockfd不合法
EINVALsockfd已经绑定到其他地址
ENOTSOCKsockfd是一个文件描述符,不是socket描述符
EACCES地址被保护,用户的权限不足
EADDRNOTAVAIL接口不存在或者绑定地址不是本地
EFAULTmy_addr指针超出用户空间
EINVAL地址长度错误,或者socket不是AF_UNIX族
ELOOP解析my_addr时符号链接过多
ENAMETOOLONGmy_addr过长
ENOENT文件不存在
ENOMEN内存内核不足
ENOTDIR不是目录
EROFSsocket节点应该在制度文件系统上

demo

	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_port = htons(1234);
	//service.sin_addr.S_un.S_un_b.s_b1 = 127;
	//service.sin_addr.S_un.S_un_b.s_b2 = 0;
	//service.sin_addr.S_un.S_un_b.s_b3 = 0;
	//service.sin_addr.S_un.S_un_b.s_b4 = 1;
	service.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int bres = bind(socketserver,(const SOCKADDR*)&service,sizeof(service));
	if (SOCKET_ERROR == bres)
	{
		int a = WSAGetLastError();
		closesocket(socketserver);
		WSACleanup();
	}

3、listen函数

作用

将套接字置于正在侦听传入连接的状态

参数

int
WSAAPI		//调用约定
listen(
    _In_ SOCKET s, 	//服务器端的socket
    _In_ int backlog		//挂起连接队列的最大长度
    );

SOMAXCONN 由系统设置最大长度 调用约定作用:
1、函数名字的编译方式 2、参数的入栈顺序 3、函数的调用时间
返回值: 成功 0 失败 SOCKET_ERROR 可以调用WSAGetLastError() 然后释放

demo:

int lres = listen(socketserver,SOMAXCONN);
if (SOCKET_ERROR == lres)
{
	int a = WSAGetLastError();
	closesocket(socketserver);
	WSACleanup();
	return 0;
}

4、accept

作用:

允许在套接字上进行连接尝试(将客户端信息创建成客户端socket,提供给服务器通信)

参数:

SOCKET
WSAAPI
accept(
    _In_ SOCKET s,//服务器端的socket
    _Out_writes_bytes_opt_(*addrlen) struct sockaddr FAR * addr, //客户端地址端口信息结构体
    _Inout_opt_ int FAR * addrlen //参数2的大小
    );

返回值

0 成功 失败 INVALID_SOCKET 可以调用WSAGetLastError() 获取失败原因然后释放

此时可以通过getpeername()获取客户端信息
getsockname()获取本地服务器信息

demo

5、recv

作用:

接受客户端发送来的消息(阻塞)

原理:

通过socket找到接受协议数据的缓冲区,并将数据复制到参数二中

函数参数

int
WSAAPI
recv(
    _In_ SOCKET s,//客户端对应的socket
    _Out_writes_bytes_to_(len, return) __out_data_source(NETWORK) char FAR * buf, //客户端消息存储空间,一般1500字节
    _In_ int len,//一般是参数二得到的字节数-1,预留‘\0’
    _In_ int flags//数据的读取方式 一般填0
    );

读取数据的方式(flag):

MSG_PEEK:读取数据后不进行删除(每次读取的内容相同) MSG_OOB:接受带外数据:传递的数据在最后字写携带特殊数据
MSG_WAITALL:等到缓冲区字节满足参数3请求的字节数后,才开始读取

返回值:

读出来的字节大小 客户端下限,返回0,释放客户端socket 执行失败
返回SOCKET_ERROR,WSAGetLastError获取错误码

demo:

char buf[1500] = { 0 };
int rres = recv(socketClient,buf,10,0);
if (0 == rres)
{
	printf("连接中断");
}
else if (SOCKET_ERROR == rres)
{
	int a = WSAGetLastError();//获取错误码
	printf("socket创建失败");
	closesocket(socketserver);
	WSACleanup();
	return 0;
}
else
{
	printf("%d, %s \n", rres, buf);
}

6、send

作用:

向目标发送数据,将数据复制到系统的协议缓冲区中,由计算机发送出去。传出单元大小为1500

参数

int
WSAAPI
send(
    _In_ SOCKET s, //目标socket
    _In_reads_bytes_(len) const char FAR * buf,//要发送数据的缓冲区
    _In_ int len,//发送的数据的字节数(超过1500会分片处理)
    _In_ int flags
    );

返回值:

成功 返回写入的字节数 失败返回SOCKET_ERROR

demo

int sres = send(socketClient, "发送字符串", sizeof("发送字符串"), 0);
if (SOCKET_ERROR == sres)
{
	int a = WSAGetLastError();//获取错误码
	printf("socket创建失败");
	closesocket(socketserver);
	WSACleanup();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值