socket学习01(socket函数参数介绍)

news/2024/5/18 14:41:13 标签: 网络, udp, tcp/ip

socket套接字函数接口参数:
1.SOCKET sock = socket(int af, int type, int protocol);
(1)af 为地址族(Address Family),IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。
**注意:127.0.0.1,它是一个特殊IP地址,表示本机地址
(2)type 为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字) 和 SOCK_DGRAM(数据报套接字/无连接的套接字)。
(3)protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。

2.int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);
(1)sock 为 socket 文件描述符。
(2)addr 为 sockaddr 结构体变量的指针。
(3)addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。
使用struct sockaddr_in结构体:
struct sockaddr_in{
sa_family_t sin_family; //地址族(Address Family),也就是地址类型
uint16_t sin_port; //16位的端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用,一般用0填充
};

struct in_addr{
in_addr_t s_addr; //32位的IP地址
};

3.int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen); 与bind类似

4.int listen(SOCKET sock, int backlog);
//被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。
sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。

5.SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);
当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。
accept() 返回一个新的套接字来和客户端通信addr 保存了客户端的IP地址和端口号而 sock 是服务器端的套接字,大家注意区分。后面和客户端通信时,要使用这个新生成的套接字。
注意:listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。
accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。

6.int send(SOCKET sock, const char *buf, int len, int flags);
sock 为要发送数据的套接字,buf 为要发送的数据的缓冲区地址,len 为要发送的数据的字节数,flags 为发送数据时的选项

7.int recv(SOCKET sock, char *buf, int len, int flags);

在这里插入图片描述

server

// Sock01.cpp : 定义控制台应用程序的入口点。
//
//#define _WINSOCK_DEPRECATED_NO_WARNINGS   //属性 预处理 添加
#include "stdafx.h"
#include<WinSock2.h>
#include<Windows.h>
//#pragma comment(lib,"ws2_32.lib")
int main()
{
	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);  //启动windows socket 2环境
	//建立简易的tcp服务端
//1
	SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);     //socket编程有三种:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW) TCP基于流式
 //2.BIND 绑定用于接受客户端连接的网络端口
	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);// host to net unsigned short
	_sin.sin_addr.S_un.S_addr = INADDR_ANY;
	if (SOCKET_ERROR == bind(_sock, (sockaddr*)&_sin, sizeof(_sin)))
	{
		printf("错误,绑定失败\n");
	}
	else
	{
		printf("绑定成功\n");
	}
	//3.listen 监听网络端口
	if (SOCKET_ERROR == listen(_sock, 5))
	{
		printf("错误,监听失败\n");
	}
	else
	{
		printf("监听成功\n");
	}
	//4.accept 等待接收客户端连接
	sockaddr_in clientAddr = {};
	int nDddrLen = sizeof(sockaddr_in);
	SOCKET _cSock = INVALID_SOCKET;
	_cSock = accept(_sock, (sockaddr*)&clientAddr, &nDddrLen);
	if (_cSock == INVALID_SOCKET)
	{
		printf("错误,接受到无效客户端socke..\n");
	}
	printf("新客户端加入:socket = %d, IP = %s\n",_cSock, inet_ntoa(clientAddr.sin_addr));
	char _recvBuf[256] = {}; //接收数据
	while (true)
	{
		//5.接收客户端请求数据
		int nLen =  recv(_cSock,_recvBuf,256,0);
		if (nLen<=0)
		{
			printf("客户端已退出,任务结束\n");
			break;
		}
		printf("收到命令:%s\n",_recvBuf);
		//6.处理请求
		if (0 == strcmp(_recvBuf,"getName"))
		{
			//7.send 向客户端发送一条数据
			char msgBuf[] = "Server0102\n";
			send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);
		}
		else if (0 == strcmp(_recvBuf, "getAge"))
		{
			//7.send 向客户端发送一条数据
			char msgBuf[] = "23\n";
			send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);
		}
		else
		{
			//7.send 向客户端发送一条数据
			char msgBuf[] = "?????\n";
			send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);
		}
		
	}

	//6.关闭套接字socket
	closesocket(_cSock);
	WSACleanup();
	printf("已退出,任务结束\n");
	getchar();
	return 0;
}


Client

// Client.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<WinSock2.h>
#include<Windows.h>
//#pragma comment(lib,"ws2_32.lib")
#include<iostream>
using namespace std;
int main()
{
	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);  //启动windows socket 2环境
							//建立简易的tcp服务端
	//1.建立一个socket
	SOCKET _sock =  socket(AF_INET,SOCK_STREAM,0);
	if (INVALID_SOCKET == _sock)
	{
		printf("错误,建立client socket失败。。\n");
	}
	else
	{
		printf("建立client socket成功\n");
	}
	//2.连接服务器
	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);
	_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int ret = connect(_sock,(sockaddr*)&_sin,sizeof(sockaddr_in));
	if (SOCKET_ERROR == ret)
	{
		printf("错误,连接socket失败。。\n");
	}
	else
	{
		printf("连接socket成功\n");
	}
	while (true)
	{
		//3.输入请求命令
		char cmdBuf[256] = {};
		scanf("%s", cmdBuf);
		//4.处理数据请求
		if (0 == strcmp(cmdBuf,"exit"))
		{
			printf("收到退出命令,任务结束\n");
			break;
		}
		else
		{
			//5.向服务器发送请求命令
			send(_sock,cmdBuf,strlen(cmdBuf)+1,0);
		}
		//6.接受服务信息 recv
		char recvBuf[256] = {};
		int nlen = recv(_sock, recvBuf, 256, 0);
		if (nlen > 0)
		{
			printf("接收到的收据:%s\n", recvBuf);
		}
	}


	//7.结束套接字
	closesocket(_sock);

	WSACleanup();
	printf("退出命令,任务结束\n");
	getchar();
	return 0;
}



http://www.niftyadmin.cn/n/1531189.html

相关文章

C++日记——Day13:基类指针、虚函数、多态性、纯虚函数、基类的析构函数

基类指针、派生类指针 父类指针可以指向子类对象 Human *phuman new Man; //父类的指针指向了一个new出来的子类对象。 phuman->func_human(); //父类指针可以调用父类的成员函数。 phuman->func_man(); //不可以&#xff0c;虽然new子类对象&#xff0c;但是父类指针…

socket学习02(发送结构化消息)

发送结构化消息 网络数据报文的格式定义&#xff1a; 报文有两部分&#xff1a;包头和包体&#xff0c;是网络消息的基本单元 包头&#xff1a;描述本次消息的大小&#xff0c;描述数据的作用 包体&#xff1a;数据 server // Sock01.cpp : 定义控制台应用程序的入口点。 // …

C++日记——Day14:友元函数、友元类、友元成员函数

友元函数&#xff1a; public、protected、private&#xff1a; 只要让func成为类Man的友元函数&#xff0c;那么func这个函数就可以访问Man的所有成员&#xff0c;private&#xff0c;protected&#xff0c;public //Man.h class Man{ private:int Age;friend void func(co…

使用LUA实现 IEEE754算法

十六进制的HEX字符串 转换成 浮点数 function hexToFloat( hexString )if hexString nil thenreturn 0endlocal t type( hexString )if t "string" thenhexString tonumber(hexString , 16)endlocal hexNums hexStringlocal sign math.modf(hexNums/(2^31))lo…

C++日记——Day15:RTTI、dynamic_cast、typeid、虚函数表

RTTI&#xff1a;Run Time Type Identification运行时类型识别 通过运行时类型识别&#xff0c;程序能够使用基类指针或者引用来检查这些指针或者引用所指向的对象的实际派生类型。 RTTI我们可以把它看成系统提供给我们的一种能力&#xff0c;这种能力是通过两个运算符来体现…

C++日记——Day16:基类与派生类关系

派生类对象模型简述&#xff1a;派生类有多个部分组成 1、一个是含有派生类自己定义的成员变量&#xff0c;成员函数的子对象。 2、一个是派生类继承的基类的子对象&#xff0c;因为派生类含有基类部分&#xff0c;所以我们可以把派生类对象当成基类对象来用&#xff08;派生…

C++日记——Day17:左值、右值、左值引用、右值引用、move

左值和右值 int i 10; 左值&#xff1a;能用在赋值语句左侧的东西&#xff0c;它能够代表一个内存地址。 右值&#xff1a;不能作为左值的值。右值不能出现在赋值语句中等号左侧 C中的一条表达式&#xff0c;要么是右值&#xff0c;要么就是左值&#xff0c;不可能两者都不…

C++日记——Day18:临时对象探讨、解析

临时对象的概念 int i 1; int &&r1 i; //r1和i之间没有关系 另外一些临时对象&#xff0c;因为我们代码的书写问题而产生。统一称临时变量为临时对象。 产生临时对象的情况与解决 class TmpValue{ public:int val1;int val2; public:TmpValue(int v10, int v20);T…