网络编程:套接字 socket

复习一下,先复习下简单的套接字。

好记性不如烂笔头,烂笔头不如烂键盘,烂键盘好过没键盘。

Windows下.........................................................................................................................

类型:

流式套接字(SOCK_STREAM)套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。TCP

数据报式套接字(SOCK_DGRAM:提供无连接服务,数据包以独立包形式发送,不提供无措保证,数据可能丢失或重复,并且接收顺序混乱。UDP

原始套接字(SOCK_RAW:原始套接字与流式和数据报套接字的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接

常用基本函数:

  • int WSAStartup(WORD,& WSADATA)

说明:加载套接字库,加载成功返回0。

参数一:指定套接字版本,高位指定主版本,低位指定副版本,可以利用MAKEWORD(x,y)生成,其中x是高位,y是低位。

参数二:用于接收WSAStartup加载的套接字库版本信息。WSADATA结构体中,第一个成员代表主版本,第二个成员代表副版本。

  • int socket(int af, int type, int protocol)

说明:创建套接字。成功返回套接字描述符。失败返回INVALID_SOCKET

参数一:指定地址族,对于TCP/IP协议 ,只能为AF_INET也可以写为PF_INET.

参数二:指定套接字类型,SOCK_STREAM为流式套接字(TCP),SOCK_DGRAM产生数据报套接字(UDP)。

参数三:指定与地址家族相关的协议,如果为0会自动分配一个合适的协议。

  • int bind( SOCKET sockaddr, const struct sockaddr FAR* my_addr,int addrlen)

说明:为套接字绑定本地地址,成功返回0,失败返回-1

参数一:通过socket()函数创建的套接字

参数二:指定的本地地址信息,类型为sockaddr结构指针变量

参数三:指定地址结构的长度,sizeof(sockaddr)

struct sockaddr {

  unsigned short sa_family; //指定地址族,必须为AF_INET

    char sa_data[14];  //占位,指定协议相关具体地址信息

};

为了方便地址填写,一般用sockaddr_in代替sockaddr,参数填写的时候进行强转即可

struct sockaddr_in {
  short int sin_family; //地址族 只能是AF_INET

    unsigned short int sin_port;   //指定端口号(要网字节序 使用函数htons()转化)

    struct in_addr sin_addr;  //套接字主机IP地址,用到in_addr结构体
    unsigned char sin_zero[8];   //填充数,使sockaddr_in和sockaddr的sizeof相等

  };

对于IP地址,如果指定为INADDR_ANY,则允许套接字向任何分配给本机机器的IP地址发送或接受数据,如果机器有多个网卡,可以简化应用程序的编写。

typedef struct in_addr {

  union {

  struct{ unsigned char s_b1,s_b2, s_b3,s_b4;} S_un_b;

  struct{ unsigned short s_w1, s_w2;} S_un_w;

    unsigned long S_addr;  // IP地址(网络字节序,利用htonl()转换)

  } S_un;

  } IN_ADDR;

inet_addr(“192.168.1.156”)会返回一个适合S_addr unsigned long类型,inet_ntoa(in_addr)则相反 ,会将一个in_addr结构体返回一个点分的字符串,”192.168.1.156”

  • int listen(int sockfd, int backlog)

说明:将套接字设置为监听模式,成功返回0,失败返回-1

参数一:套接字描述符socket()函数创建的套接字

参数而:等待连接队列的最大长度(并不是在一个端口连接数)

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

说明:等待客户连接,并接受客户连接。请求成功,返回一个相对于连接的新的套接字,原先的套接字,继续监听连接请求,失败返回INVALID_SOCKET

参数一:套接字描述符

参数二:保存发起连接的套接字的IP和端口信息,也利用sockaddr_in代替sockaddr

参数三:保存返回的套接字地址长度,必须要赋初值,sizeof(sockaddr)

  • int connect (SOCKET s, const struct sockaddr * name, int namelen )

说明:与指定套接字建立连接,成功返回0,失败返回SOCKET_ERROR,也就是-1.

参数一:套接字描述符

参数二:指定要连接的套接字的地址,也就是服务端的

参数三:地址长度

  • int send(SOCKET s, const char FAR *buf, int len, int flags) / sendto

说明:向指定套接字发送数据,send用于TCP连接,sento用于UDP连接,并且sendto多了两个参数,用来指定服务端的地址和长度。成功返回发送数据长度,失败返回SOCKET_ERROR

参数一:指定接收端套接字,即通过accept()接受的套接字

参数二:要发送的字符数据

参数三:带发送数据的长度

参数四:执行方式,影响send的调用行为,一般设为0

  • int recv(SOCKET s, char FAR *buf, int len, int flags) / recvfrom

说明:接收指定套接字数据,recv用于TCP连接,recvfrom用于UDP连接,并且recvfrom多了两个参数,用来指定服务端的地址和长度,并且接收地址长度的参数必须初始化。成功返回接收数据长度,失败返回-1

参数一:指定接收端的套接字

参数二:存储数据的缓冲区

参数三:缓冲区大小

参数四:执行方式

  • closesocket(socket)

说明:关闭套接字

  • WSACleanup()

说明:终止对套接字库的使用

  • int WSAGetLastError()  / GetLastError()

说明:返回一个int类型的Winsock错误代码,对于上述函数执行返回失败,都可以利用该函数进行捕捉错误。

TCP和UDP连接:

TCP:面向连接的,可靠的

(1)数据传输过程必须经过建立连接、维护连接和释放连接3个阶段

(2)在传输过程中,不需要携带目的主机的地址

(3)可靠,协议复杂,通信效率不低

UDP:面向无连接的,不可靠

(1)不需要连接

(2)每个分组都携带完整的目的主机地址,在系统中独立传送

(3)没有顺序控制,接收方的分组可能出现乱序、重复和丢失现象

(4)通信效率高,不可靠

TCP例子:

图片 哪儿来的?

服务端:

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
using namespace std;

int main()
{
	WORD word = MAKEWORD(2, 0);
	WSADATA wsaData;
	if (WSAStartup(word, &wsaData) != 0)
	{
		printf("套接字库加载失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		return -1;
	}
	if (LOBYTE(wsaData.wVersion != 2) || HIBYTE(wsaData.wHighVersion != 0))
	{
		printf("套接字库加载失败!\n");
		WSACleanup();
		return -1;
	}

	int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
	if (sockSrv == INVALID_SOCKET)
	{
		printf("套接字创建失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	sockaddr_in addrSrv;
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_port = htons(6666);

	if (int res = bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))!= 0)
	{
		printf("套接字绑定失败!");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	if (int res = listen(sockSrv, 5) != 0)
	{
		printf("监听套接字失败!");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	sockaddr_in addrClient;
	int addrlen;
	while (1)
	{
		addrlen = sizeof(SOCKADDR);
		int sockClient = accept(sockSrv, (SOCKADDR*)&addrClient, &addrlen);
		if (sockClient == INVALID_SOCKET)
		{
			printf("套接字连接失败!");
			int err = GetLastError();
			printf("errNum = %d\n", err);
			continue;
		}
		char sendBuf[200] = { 0 };
		char recvBuf[200] = { 0 };
		sprintf(sendBuf, "hello ,this is %s", inet_ntoa(addrSrv.sin_addr));
		send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);

		recv(sockClient, recvBuf, sizeof(recvBuf), 0);
		printf("%s\n", recvBuf);
		closesocket(sockClient);
	}

	closesocket(sockSrv);
	WSACleanup();

	system("pause");
	return 0;
}

客户端:

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
using namespace std;

int main()
{
	WORD word = MAKEWORD(2, 0);
	WSADATA wsaData;
	if (WSAStartup(word, &wsaData) != 0)
	{
		printf("套接字库加载失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		return -1;
	}
	if (LOBYTE(wsaData.wVersion != 2) || HIBYTE(wsaData.wHighVersion != 0))
	{
		printf("套接字库加载失败!\n");
		WSACleanup();
		return -1;
	}

	int sockClient = socket(AF_INET, SOCK_STREAM, 0);
	if (sockClient == INVALID_SOCKET)
	{
		printf("套接字创建失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	sockaddr_in addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6666);

	if (connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)) != 0)
	{
		printf("套接字连接失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	char recvBuf[200] = { 0 };
	char sendBuf[200] = { 0 };

	int recvLen = recv(sockClient, recvBuf, sizeof(recvBuf), 0);
	printf("%s\n",recvBuf);

	sprintf(sendBuf," my name is zhangsan");
	send(sockClient,sendBuf,strlen(sendBuf)+1,0);
	
	closesocket(sockClient);
	WSACleanup();

	system("pause");
	return 0;
}

UDP例子:

服务端:

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
using namespace std;

int main()
{
	WORD word = MAKEWORD(2, 0);
	WSADATA wsaData;
	if (WSAStartup(word, &wsaData) != 0)
	{
		printf("套接字库加载失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		return -1;
	}
	if (LOBYTE(wsaData.wVersion != 2) || HIBYTE(wsaData.wHighVersion != 0))
	{
		printf("套接字库加载失败!\n");
		return -1;
		WSACleanup();
	}

	int sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockSrv == INVALID_SOCKET)
	{
		printf("创建套接字失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	sockaddr_in addrSrv;
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_port = htons(6000);

	if (bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)) != 0)
	{
		printf("套接字绑定失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	sockaddr_in addrClient;
	int addrlen = sizeof(SOCKADDR);
	while (1)
	{
		char sendBuf[200] = { 0 };
		char recvBuf[200] = { 0 };
		
		int recvLen = recvfrom(sockSrv, recvBuf, sizeof(recvBuf), 0, (SOCKADDR*)&addrClient, &addrlen);
		if (recvLen > 0)
		{
			printf("%s\n", recvBuf);
		}
		sprintf(sendBuf, "hello ,this is %s", inet_ntoa(addrSrv.sin_addr));
		sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrClient, addrlen);

	}

	closesocket(sockSrv);
	WSACleanup();

	system("pause");
	return 0;
}

客户端:

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
using namespace std;

int main()
{
	WORD word = MAKEWORD(2, 0);
	WSADATA wsaData;
	if (WSAStartup(word, &wsaData) != 0)
	{
		printf("套接字库加载失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		return -1;
	}
	if (LOBYTE(wsaData.wVersion != 2) || HIBYTE(wsaData.wHighVersion != 0))
	{
		printf("套接字库加载失败!\n");
		return -1;
		WSACleanup();
	}

	int sockClient = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockClient == INVALID_SOCKET)
	{
		printf("创建套接字失败!\n");
		int err = GetLastError();
		printf("errNum = %d\n", err);
		WSACleanup();
		return -1;
	}

	sockaddr_in addrSrv;
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addrSrv.sin_port = htons(6000);
	int addrlen = sizeof(SOCKADDR);


	char sendBuf[200] = { 0 };
	char recvBuf[200] = { 0 };
	sprintf(sendBuf, "my name is demaxiya", inet_ntoa(addrSrv.sin_addr));
	sendto(sockClient, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrSrv, addrlen);
	int recvLen = recvfrom(sockClient, recvBuf, sizeof(recvBuf), 0,(SOCKADDR*)&addrSrv, &addrlen);
	if (recvLen > 0)
	{
		printf("%s\n", recvBuf);
	}

	closesocket(sockClient);
	WSACleanup();

	system("pause");
	return 0;
}

错误不知道有没有,有也别慌。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值