Socket学习------函数学习

#  非原创,只是整合了别人的资料的结果,做了一下综合;原版学习网址

1、getaddrinfo

getaddrinfo()函数的学习,这个是直接帮助你写好你对应的sturct addrinfo这个是数据结构;由于之前是需要使用gethostbyname()来进行DNS的查询的,然后需要手动地进行调用的调节。但是这个函数是不需要执行这些操作,函数内部已经封装好了。

 
 
int getaddrinfo(const char* node,const char* service, const struct addrinfo *hints,struct addrinfo **res);

对于参数的解析,node是要解析的主机名或者是IP地址;service是端口号或者是对应的服务的名称;hints是一个已经填好了相关资料的struct addrinfo结构体

res是一个返回的指向链表的指针

使用的时候,先判断该函数的返回值是不是为0;不为0表示得到对应的信息是错误的,需要退出。可以先赋值,再判断值的大小。

对应参数,AF_UNSPEC是不管使用的是 IPv4 还是 IPv6;这个时候赋值的变量的对应的ai_addr是一个不确定的值,因此在这里,在之后,对应的 sockaddr_in 和 sockaddr_in6 的操作是需要对应的强制类型转换

inet_ntop(1、2、3、4)

1:对应的网络类型,由ai_family提供,或者手动指定AF_INET或者AF_INET6对应的操作;2、对应的sockaddr中间的addr的地址,有sin_addr和sin6_addr这两种;3、需要保存对应数值的字符串数组;4、字符串数组的大小

事例代码:

#include<WinSock2.h>  #对应着Linux下的sys/socket.h
#include<WS2tcpip.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>


#pragma comment(lib,"WS2_32")

int main(int argc, char *argv[])
{
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
	{
		fprintf(stderr, "WSAStartup failed.\n");
		exit(1);
	}

	struct addrinfo hints, *res, *p;
	int status;
	char ipstr[INET6_ADDRSTRLEN];

	if (argc != 2)
	{
		fprintf(stderr,"usage: showip hostname\n");
		return 1;
	}
	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	if ((status = getaddrinfo(argv[1],NULL,&hints,&res))!=0)
	{
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
		return 2;
	}
	printf("IP addresses for %s:\n\n",argv[1]);

	for (p = res; p != NULL; p = p->ai_next)
	{
		void *addr;
		char *ipver;
		if (p->ai_family == AF_INET)
		{
			struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
			addr = &(ipv4->sin_addr);
			ipver = (char *)"IPv4";
		}
		else
		{
			struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
			addr = &(ipv6->sin6_addr);
			ipver = (char *)"IPv6";
		}
		inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
		printf("  %s:  %s\n", ipver, ipstr);
	}
	freeaddrinfo(res);

	system("pause");
	return 0;
}

2、socket

int socket(int domain, int type, int protocol);

{ IPv4/IPv6;  stream/datagram;  TCP/UDP}

domain: 对应的是PE_INET 和 PE_INET6,type是决定是流数据还是数据包数据;protocol是表示选择的协议

socket() 会单纯的返回一个之后system call 要使用的socket descriptor 给你,错误的时候会给你-1。error 是全局变量会设置为该错误的值。返回的这个值相当于一个端口号,被使用的时候,在bind的时候使用。

3、bind

int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

sockfd是socket()传回的socket的文件描述符。my_addr是指向的你的地址资料、名称和IP地址的struct scokaddr的指针;addrlen是以byte为单位的地址长度。

bind()在错误的时候,会返回-1;并且设置errno为该错误的值

4、connet 用法和bind几乎一样

5、listen

int listen(int sockfd, int backlog);

sockfd 是 socket() 的文件描述符;backlog 是进入的队列允许的连接的数目。表示进入的连接将会在这个队列中排队等待,直到accept()处理的,对应的就有排队的数量的限制。

listen()在错误的时候,会返回-1;并且设置errno为该错误的值

对应的使用:在调用listen的时候,我们需要先调用bind告诉对应的应该需要的连接到那个port

6、accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd:是listen的socket 文件描述符;addr:是一个local sockaddr_storage 的指针,但是使用的时候需要强制类型转换一下;addrlen:对应的local的整数变量

accept:远端的人想要使用connect()对当前的listen()的port端口进行连接,之后,会被accept进行处理。此时,会得到一个新的文件描述符,这个文件描述符是给send和recv使用的。

7、send

int send(int sockfd, const void *msg, int len, int flags);

sockfd:对应端口的socket 文件描述符(不管是socket还是accept);msg:待传送的消息;len:消息的长度(byte为单位);flag :强行置为0就好。

注意:send的返回值与len的值不相符的话,就需要再送出字串的剩下的部分;理论上,如果数据包很小的话,就会有就会一次性送出所有的东西

8、recv

int recv(int sockfd, void *buf, int len, int flags);

buf:是读到的资料缓冲区;len:最大的数据包的长度

当recv得到的值为0的时候,表示的是远端已经关闭了连接。可以通过判断这个值来判断连接是否中断

9、sendto

sendto(int sockfd, const void *msg, int len, unsigned int flags,
const struct sockaddr *to, socklen_t tolen);
to:是一个指向struct sockaddr的指针,这个包含了IP地址和端口号

之所以使用struct sockaddr_storage是因为不知道中间到底需要的是IPv4还是IPv6,因此采用泛型的处理







猜你喜欢

转载自blog.csdn.net/skd621/article/details/80518871