windows网络编程

本文介绍了Windows Socket编程的基本概念,包括阻塞式和非阻塞式的Socket通信。展示了使用C++实现的阻塞式Socket服务器和客户端代码,以及非阻塞式的Socket服务器和客户端代码。非阻塞式Socket编程中,通过Select模型、事件通知管理和完成端口管理等方式实现了重叠I/O操作,提高了服务器的并发处理能力。此外,还涉及到了文件传输和邮件发送的Socket应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

socket网络编程

阻塞式socket编程

服务器代码

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
    //初始化WSA
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsaData;
    if(WSAStartup(sockVersion, &wsaData)!=0)
    {
        return 0;
    }
    //创建套接字
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(slisten == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }
	
    //绑定IP和端口
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8888);
    //sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
    sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error !");
    }
    //开始监听
    if(listen(slisten, 5) == SOCKET_ERROR)
    {
        printf("listen error !");
        return 0;
    }
    //循环接收数据
    SOCKET sClient;
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    char revData[255]; 
    while (true)
    {
        printf("等待连接...\n");
        sClient = accept(slisten, (sockaddr *)&remoteAddr, &nAddrlen);
        if(sClient == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }
        printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
        
		//发送数据
        const char * sendData = "你好,TCP客户端!\n";
        send(sClient, sendData, strlen(sendData), 0);

        //接收数据
        int ret = recv(sClient, revData, 255, 0);        
        if(ret > 0)
        {
            revData[ret] = 0x00;
            printf(revData);
			printf("\n");
        }
        closesocket(sClient);
    }
    
    closesocket(slisten);
    WSACleanup();
    return 0;
}

客户端代码

#include<iostream>
#include<winsock2.h>
#include<string.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main()
{
	WSADATA wsData;
	WORD wVersionrequest=MAKEWORD(2,2);
	int ret=WSAStartup(wVersionrequest,&wsData);
	if (!ret)  
    {  
        printf("客户端嵌套字已经打开!\n");  
    }  
    else  
    {  
        printf("客户端的嵌套字打开失败!\n");  
        return 0;//结束  
    }  
	//创建套接字
	SOCKET sockclient=socket(AF_INET,SOCK_STREAM,0);
	if(sockclient==INVALID_SOCKET)
	{
	cout<<"socket() fail:"<<WSAGetLastError()<<endl;
	}
	sockaddr_in clietaddr;
	memset(&clietaddr,0,sizeof(clietaddr));
	clietaddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	clietaddr.sin_family=AF_INET;
	clietaddr.sin_port=htons(8888);

	int retval;
	if(retval=connect(sockclient,(sockaddr*)&clietaddr,sizeof(clietaddr))==SOCKET_ERROR)
	{
		printf("connect() failed:%d\n",WSAGetLastError());
		return 1;
	}

	char recvBuf[MAXBYTE]={0};
	recv(sockclient,recvBuf,MAXBYTE+1,NULL);
	printf("Message from server:%s\n",recvBuf);     

	char sendbuf[1024]={"hello server"};

	send(sockclient,sendbuf,1024,0);
               
	
	//关闭套接字
	closesocket(sockclient);
	//终止使用DLL
	WSACleanup();

	system("pause");
	return 0;


}

/*
#include <winsock2.h>
#include <iostream>

#include <string.h>
using namespace std;

#pragma comment(lib, "ws2_32.lib")			//add ws2_32.lib


const int DEFAULT_PORT = 8000;
int main(int argc,char* argv[])
{
	
	WORD	wVersionRequested;
	WSADATA wsaData;
	int		err,iLen;
	wVersionRequested	=	MAKEWORD(2,2);//create 16bit data
	//(1)Load WinSock
	err	=	WSAStartup(wVersionRequested,&wsaData);	//load win socket
	if(err!=0)
	{
		cout<<"Load WinSock Failed!";
		return -1;
	}
	//(2)create socket
	SOCKET sockClt = socket(AF_INET,SOCK_STREAM,0);
	if(sockClt == INVALID_SOCKET){
		cout<<"socket() fail:"<<WSAGetLastError()<<endl;
		return -2;
	}
	//(3)IP
	SOCKADDR_IN addrSrv;
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
	addrSrv.sin_port = htons(DEFAULT_PORT);
	
	//(5)connect
	err = connect(sockClt,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
	
	if(err ==INVALID_SOCKET)
	{
		cout<<"connect() fail"<<WSAGetLastError()<<endl;
		return -1;
	}
	
	char sendBuf[1024],hostname[100];
	if(gethostname(hostname,100)!=0)	//get host name
		strcpy(hostname,"None");
	strcpy(sendBuf,hostname);
	strcat(sendBuf,"have connected to you!");
	err = send(sockClt,sendBuf,strlen(sendBuf)+1,0);
	
	char recvBuf[1024]="\0";
	iLen = recv(sockClt,recvBuf,1024,0);
	
	if(iLen ==0)
		return -3;
	else if(iLen==SOCKET_ERROR){
		cout<<"recv() fail:"<<WSAGetLastError()<<endl;
		return -4;
	}
	else
	{
		recvBuf[iLen] = '\0';
		cout<<recvBuf<<endl;
	}
	closesocket(sockClt);
	
	WSACleanup();
	system("PAUSE");
	return 0;
}
*/

非阻塞式socket编程

客户端代码

#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
#include<string.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main()
{
	char buf[BUFSIZ];
	WSADATA wsData;
	WORD wVersionrequest = MAKEWORD(2, 2);
	int ret = WSAStartup(wVersionrequest, &wsData);
	if (!ret)
	{
		printf("客户端嵌套字已经打开!\n");
	}
	else
	{
		printf("客户端的嵌套字打开失败!\n");
		return 0;//结束  
	}
	//创建套接字
	SOCKET sockclient = socket(AF_INET, SOCK_STREAM, 0);
	if (sockclient == INVALID_SOCKET)
	{
		cout << "socket() fail:" << WSAGetLastError() << endl;
	}
	sockaddr_in clietaddr;
	memset(&clietaddr, 0, sizeof(clietaddr));
	clietaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	clietaddr.sin_family = AF_INET;
	clietaddr.sin_port = htons(8888);

	int retval;
	int iMode = 1;
	retval = ioctlsocket(sockclient, FIONBIO, (u_long*)&iMode);
	if (retval == SOCKET_ERROR)
	{
		printf("ioctlsocket failed!\n");
		WSACleanup();
		return -1;
	}

	//循环等待
	while (TRUE)
	{
		//调用connect函数可以将客户端连接到服务器
		if (retval = connect(sockclient, (sockaddr*)&clietaddr, sizeof(clietaddr)) == SOCKET_ERROR)
		{
			int err = WSAGetLastError();
			//无法立即完成非阻塞socket上的操作
			if (err == WSAEWOULDBLOCK || err == WSAEINVAL)
			{
				Sleep(500);
				continue;
			}
			else if (err == WSAEISCONN)			//已建立连接
			{
				break;
			}
			else
			{
				printf("connect() failed:%d\n", WSAGetLastError());
				closesocket(sockclient);
				WSACleanup();
				return -1;
			}
			
		}
		
	}
	//循环向服务器发送字符串,并显示反馈信息
	//发送"quit"将使服务器程序退出,同时客户端程序自身也将退出
	while (TRUE)
	{
		//向服务器发送数据
		printf("Please input a string to send: ");
		//接收输入的数据
		char str[1024];
		scanf("%s", str);
		
		//将用户输入的数据复制到buf中
		ZeroMemory(buf, BUFSIZ);
		strcpy(buf, str);
		//循环等待
		while (TRUE)
		{
			//向服务器发送数据
			retval = send(sockclient, buf, strlen(buf), 0);
			if (SOCKET_ERROR == retval)
			{
				int err = WSAGetLastError();
				if (err == WSAEWOULDBLOCK)
				{
					Sleep(500);
					continue;
				}
				else
				{
					printf("send failed!\n");
					closesocket(sockclient);
					WSACleanup();
					return -1;
				}
			}
			break;
		}

		while (true)
		{
			ZeroMemory(buf, BUFSIZ);				//清空接收数据的缓冲区
			retval = recv(sockclient, buf, sizeof(buf) + 1, 0);//接收服务器的回传数据
			if (SOCKET_ERROR == retval)
			{
				int err = WSAGetLastError();		//获取错误编码
				if (err == WSAEWOULDBLOCK)			//接收数据缓冲区暂无数据
				{
					Sleep(100);
					//printf("waiting back msg!\n");
					continue;
				}
				else if (err == WSAETIMEDOUT || err == WSAENETDOWN)
				{
					printf("recv failed!\n");
					closesocket(sockclient);
					WSACleanup();
					return -1;
				}
				break;
			}
			break;
		}
		
		printf("Recv From Server:%s\n", buf);
		//如果收到"quit"则退出
		if (strcmp(buf, "quit") == 0)
		{
			printf("quit!\n");
			break;
		}
	}
}

服务端代码

#define  _CRT_SECURE_NO_WARNINGS
#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}
	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		return 0;
	}

	//绑定IP和端口
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	//sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
	sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("bind error !");
	}
	//开始监听

	/*if(listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !");
		return 0;
	}
	*/
	

	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !");
		return 0;
	}
	
	int iMode = 1;
	int retval = ioctlsocket(slisten, FIONBIO, (u_long*)&iMode);
	if (retval == SOCKET_ERROR)
	{
		printf("ioctlsocket failed!\n");
		WSACleanup();
		return -1;
	}
	
	printf("TCP Server start...\n");

	//循环接收数据
	SOCKET sClient;
	sockaddr_in remoteAddr;
	int nAddrlen = sizeof(remoteAddr);
	
	while (true)
	{

		sClient = accept(slisten, (sockaddr*)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			int err = WSAGetLastError();
			if (err == WSAEWOULDBLOCK)		//无法立既完成非阻塞Socket上的操作
			{
				Sleep(100);
				continue;
			}
			else
			{
				printf("accept failed!\n");
				closesocket(sClient);
				WSACleanup();
				return -1;

			}
		}
		break;
	}
	char buf[1024] = { '\0' };

	char sendData[100] = "你好,TCP客户端!\n";
	send(sClient, sendData, strlen(sendData), 0);

	//循环接收客户端数据,直到客户端发送quit命令后退出。
	while (TRUE)
	{
		ZeroMemory(buf, 1024);		//清空接收数据的缓冲区
		retval = recv(sClient, buf, 1024, 0);	//接收来自客户端的数据,因为是非阻塞式,所以即使没有数据也会继续

		if (SOCKET_ERROR == retval)
		{
			INT ERR = WSAGetLastError();//获取错误编码
			if (ERR == WSAEWOULDBLOCK)		//接收数据缓冲区暂无数据
			{
				Sleep(100);
				continue;
			}
			else if (ERR == WSAETIMEDOUT || ERR == WSAENETDOWN)
			{
				printf("recv failed!\n");
				closesocket(slisten);
				WSACleanup();
				return -1;
			}
		}
		//获取当前系统时间
		SYSTEMTIME st;
		GetLocalTime(&st);
		char sDateTime[30];
		sprintf(sDateTime, "%4d-%2d-%2d%2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		//打印输出信息
		printf("%s,Recv From Client [%s:%d]:%s\n", sDateTime, inet_ntoa(remoteAddr.sin_addr), remoteAddr.sin_port, buf);

		//如果客户端发送quit字符串,则服务器退出
		if (strcmp(buf, "quit") == 0)
		{
			retval = send(sClient, "quit", strlen("quit"), 0);
			break;
		}
		else
		{
			char msg[1024];
			//sprintf(msg, "Message recvived - %s", buf);
			while (TRUE)
			{
				memset(msg, 0, 1024);
				printf("请输入聊天信息\n");
				scanf("%s", msg);
				//向服务器发送数据
				retval = send(sClient, msg, strlen(msg), 0);
				if (SOCKET_ERROR == retval)
				{
					int err = WSAGetLastError();
					printf("%d", err);
					if (err == WSAEWOULDBLOCK)
					{
						Sleep(500);
						continue;
					}
					else
					{
						printf("send failed!\n");
						closesocket(slisten);
						closesocket(sClient);
						WSACleanup();
						return -1;`1
					}
				}
				break;
			}
		}
	}
}

服务端代码Select 模型代码

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <winsock2.h>
#include <iostream>

#pragma comment(lib, "WS2_32.lib")

#define PORT 9999
#define DATA_BUFSIZE 8192

typedef struct _SOCKET_INFORMATION {
    CHAR Buffer[DATA_BUFSIZE];        //发送和接收数据的缓冲区
    WSABUF DataBuf;                    //定义发送和接收数据缓冲区的结构体,包括缓冲区长度和内容
    SOCKET Socket;                    //与客户端进行通信的套接字
    DWORD BytesSEND;                //保存套接字发送的字节数
    DWORD BytesRECV;                //保存套接字接收的字节数
} SOCKET_INFOMATION, * LPSOCKET_INFORMATION;

//记录正在使用的套接字总数量
DWORD TotalSockets = 0;

//保存Socket信息对象的数组,FD_SETSIZE表示SELECT模型中允许的最大Socket数量,
//常量FD_SETSIZE=64,默认select()函数最多处理64个套接字
LPSOCKET_INFORMATION SocketArray[FD_SETSIZE];

//为指定的Socket创建对应的SOCKET_INFORMATION结构体,将其添加到SocketArray数组中
bool CreateSocketInformation(SOCKET s)
{
    LPSOCKET_INFORMATION SI;    //用于保存套接字的信息
    //为SI分配内存空间
    if ((SI = (LPSOCKET_INFORMATION)GlobalAlloc(GPTR, sizeof SOCKET_INFOMATION)) == NULL)
    {
        printf("GlobalAlloc()   failed   with   error   %d\n", GetLastError());
        return   FALSE;
    }

    //初始化SI的值
    SI->Socket = s;
    SI->BytesSEND = 0;
    SI->BytesRECV = 0;
    //在SocketArray数组中增加一个新元素,用于保存SI对象
    SocketArray[TotalSockets] = SI;
    TotalSockets++;                 //增加Socket数量

    return true;
}

//调用FreeSocketInformation()函数可以删除指定Socket对应的SOCKET_INFORMATION结构体,并关闭该socket
void FreeSocketInformation(DWORD Index)
{
    //获取指定索引对应的LPSOCKET_INFORMATION对象
    LPSOCKET_INFORMATION SI = SocketArray[Index];
    DWORD i;

    closesocket(SI->Socket);            //关闭Socket
    //printf("Closing socket number %d\n",SI->Socket);

    //释放指定LPSOCKET_INFORMATION对象资源
    GlobalFree(SI);
    //将数组中Index索引后面的元素前移
    if (Index != (TotalSockets - 1))
    {
        for (i = Index; i < TotalSockets; i++)
        {
            SocketArray[i] = SocketArray[i + 1];
        }
    }

    TotalSockets--;                 //socket总数减1
}

int main()
{
    SOCKET ListenSocket;        //监听套接字
    SOCKET AcceptSocket;        //与客户端通信的套接字
    SOCKADDR_IN InternetAddr;    //服务器地址
    WSADATA wsaData;
    int Ret;

    FD_SET WriteSet;            //获取可写套接字集合
    FD_SET ReadSet;                //获取可读性套接字集合
    DWORD Total = 0;            //处于就绪状态的套接字
    DWORD SendBytes;            //发送套接字
    DWORD RecvBytes;            //接收的套接字

    //初始化WinSock环境
    if ((Ret = WSAStartup(MAKEWORD(2, 2), &wsaData) != 0))
    {
        printf("WSAStartup()   failed   with   error   %d\n", Ret);
        WSACleanup();
        return -1;
    }

    //创建用于监听的套接字
    if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
    {
        printf("WSASocket()   failed   with   error   %d\n", WSAGetLastError());
        return -1;
    }

    //设置监听地址和端口
    InternetAddr.sin_family = AF_INET;
    InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    InternetAddr.sin_port = htons(PORT);

    //绑定监听套接字到本地地址和端口
    if (bind(ListenSocket, (PSOCKADDR)&InternetAddr, sizeof InternetAddr) == INVALID_SOCKET)
    {
        printf("bind()   failed   with   error   %d\n", WSAGetLastError());
        return -1;
    }

    //开始监听
    if (listen(ListenSocket, 5))
    {
        printf("listen()   failed   with   error   %d\n", WSAGetLastError());
        return -1;
    }

    //设置成非阻塞方式
    ULONG NonBlock = 1;
    if (ioctlsocket(ListenSocket, FIONBIO, &NonBlock)==SOCKET_ERROR)
    {
        printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
        return -1;
    }

    CreateSocketInformation(ListenSocket);//ListenSocket套接字创建对应的SOCKET_INFORMATION,把ListenSocket添加到SocketArray数组中
    timeval  sTime;
    sTime.tv_sec = 3;
    sTime.tv_usec = 0;
    while (true)
    {
        FD_ZERO(&ReadSet);//读套接字清零
        FD_ZERO(&WriteSet);//写套接字清零

        FD_SET(ListenSocket, &ReadSet);//向ReadSet中添加监听套接字ListenSocket
        //将SocketArray数组中的所有Socket添加到WriteSet和ReadSet集合中
        //SocketArray数组中保存着监听Socket和所有与客户端进行通信的Socket
        //这样就可以使用select()判断哪个socket有接入数据或者读取/写入数据
        for (DWORD i = 0; i < TotalSockets; ++i)
        {
            LPSOCKET_INFORMATION SocketInfo = SocketArray[i];
            FD_SET(SocketInfo->Socket, &ReadSet);
            FD_SET(SocketInfo->Socket, &WriteSet);
        }

        if ((Total = select(0, &ReadSet, &WriteSet, NULL,&sTime)) == SOCKET_ERROR) {//刚开始为什么监听套接字没有可写返回,而与客户端连接的套接字总是可写???
            printf("select()   returned   with   error   %d\n", WSAGetLastError());
            return -1;
        }

        //依次处理所有Socket。本服务器是一个回应服务器,即将从客户端收到的字符串再发回到客户端
        for (DWORD i = 0; i < TotalSockets; i++)
        {
            //SocketInfo为当前要处理的Socket信息
            LPSOCKET_INFORMATION SocketInfo = SocketArray[i];//SocketArray保存了所有监听的可读和可写的套接字
            if (FD_ISSET(SocketInfo->Socket, &ReadSet))//判断套接字是否可读,即是否有接入的连接请求或者可以接收数据
            {
                //对于监听套接字表示有新的客户端连接
                if (SocketInfo->Socket == ListenSocket)
                {
                    Total--;                    //就绪的Socket减1
                    //接受连接请求,得到与客户端进行通信的Socket AcceptSocket
                    if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET)
                    {
                        //设置Socket Accept为非阻塞模式
                        //这样服务器在调用WSASend()函数发送数据时就不会被阻塞
                        NonBlock = 1;
                        if (ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)//设置AcceptSocket套接字为非阻塞套接字,这样与客户端通信就不会阻塞了
                        {
                            printf("ioctlsocket()   failed   with   error   %d\n", WSAGetLastError());
                            return -1;
                        }
                        //创建套接字信息,初始化LPSOCKET_INFORMATION结构体数据,将AcceptSocket添加到SocketArray数组中,
                        if (CreateSocketInformation(AcceptSocket) == false)
                        {
                            return -1;
                        }
                    }
                    else
                    {
                        if (WSAGetLastError() != WSAEWOULDBLOCK)
                        {
                            printf("accept()   failed   with   error   %d\n", WSAGetLastError());
                            return -1;
                        }
                    }
                }
                else//接收数据
                {
                    //如果当前Socket在ReadSet集合中,则表明该Socket上有可以读取的数据
                    if (FD_ISSET(SocketInfo->Socket, &ReadSet))
                    {
                        Total--;                        //减少一个处于就绪状态的套接字
                        memset(SocketInfo->Buffer, 0, sizeof SocketInfo->Buffer);   //初始缓冲区
                        SocketInfo->DataBuf.buf = SocketInfo->Buffer;               //初始缓冲区位置
                        SocketInfo->DataBuf.len = DATA_BUFSIZE;                     //初始缓冲区长度
                        //接收数据  
                        DWORD Flags = 0;
                        if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR)
                        {
                            //错误编码等于WSAEWOULDBLOCK表示暂没有数据,否则表示出现异常
                            if (WSAGetLastError() != WSAEWOULDBLOCK)
                            {
                                printf("WSARecv()   failed   with   error   %d\n", WSAGetLastError());
                                FreeSocketInformation(i);           
                            }
                            continue;
                        }
                        else                //接收数据
                        {
                            SocketInfo->BytesRECV = RecvBytes;          //记录接收数据的字节数
                            //SocketInfo->DataBuf.buf[RecvBytes] = '\0'; 
                            if (RecvBytes == 0)                          //如果接收到0个字节,则表示对方已关闭连接
                            {
                                FreeSocketInformation(i);
                                continue;
                            }
                            else
                            {
                                std::cout << SocketInfo->DataBuf.buf << std::endl;// 如果成功接收数据,则打印收到的数据
                            }
                        }
                    }
                }
            }
            else                                                                  //发送数据
            {
                //如果当前Socket在WriteSet集合上,则表明该Socket的内部数据缓冲区中有数据可以发送
                if (FD_ISSET(SocketInfo->Socket, &WriteSet))//可写会一直被调用,判断大于其写缓冲的最低水位
                {
                    Total--;
                    SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;// 初始化缓冲区位置
                    SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND;// 初始化缓冲区长度

                    if (SocketInfo->DataBuf.len > 0)// 如果有需要发送的数据,则发送数据
                    {
                        if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0, NULL, NULL) == SOCKET_ERROR)
                        {
                            //错误编码等于WSAEWOULDBLOCK表示暂没有数据,否则表示出现异常
                            if (WSAEWOULDBLOCK != WSAGetLastError())
                            {
                                printf("WSASend()   failed   with   error   %d\n", WSAGetLastError());
                                FreeSocketInformation(i);                           //释放socket信息
                            }
                            continue;
                        }
                        else
                        {
                            SocketInfo->BytesSEND += SendBytes;        //记录发送数据的字节数目
                            //如果从客户端接收到的数据都已经发回到客户端
                            //则将发送和接收的字节数量设置为0
                            if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
                            {
                                SocketInfo->BytesSEND = 0;
                                SocketInfo->BytesRECV = 0;
                            }
                        }
                    }
                }
            }
        }
    }
    //system("pause");
    return 0;
}

Windows API多线程非阻塞式服务器

#define  _CRT_SECURE_NO_WARNINGS
#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI AnswerThread(LPVOID lparam);
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
int main(int argc, char* argv[])
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}
	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		return 0;
	}

	//绑定IP和端口
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	//sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
	sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("bind error !");
	}
	//开始监听

	/*if(listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !");
		return 0;
	}
	*/


	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !");
		return 0;
	}

	int iMode = 1;
	int retval = ioctlsocket(slisten, FIONBIO, (u_long*)&iMode);
	if (retval == SOCKET_ERROR)
	{
		printf("ioctlsocket failed!\n");
		WSACleanup();
		return -1;
	}
	//接收客户请求
	printf("TCP Server start...\n");

	//循环接收数据
	SOCKET sClient;


	while (true)
	{

		sClient = accept(slisten, (sockaddr*)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			int err = WSAGetLastError();
			if (err == WSAEWOULDBLOCK)		//无法立既完成非阻塞Socket上的操作
			{
				Sleep(100);
				continue;
			}
			
		}

		DWORD dwThreadId;
		CreateThread(NULL, NULL, AnswerThread, (LPVOID)sClient, 0, &dwThreadId);

	}
}


DWORD WINAPI AnswerThread(LPVOID lparam)
{
	char buf[1024] = { '\0' };
	int retval;

	char sendData[100] = "你好,TCP客户端!\n";

	//将参数lparam转换为与客户端进行通信的Socket句柄
	SOCKET sClient = (SOCKET)(LPVOID)lparam;
	send(sClient, sendData, strlen(sendData), 0);

	//循环接收客户端数据,直到客户端发送quit命令后退出。
	while (TRUE)
	{
		ZeroMemory(buf, 1024);		//清空接收数据的缓冲区
		retval = recv(sClient, buf, 1024, 0);	//接收来自客户端的数据,因为是非阻塞式,所以即使没有数据也会继续

		if (SOCKET_ERROR == retval)
		{
			INT ERR = WSAGetLastError();//获取错误编码
			if (ERR == WSAEWOULDBLOCK)		//接收数据缓冲区暂无数据
			{
				Sleep(100);
				continue;
			}
			else if (ERR == WSAETIMEDOUT || ERR == WSAENETDOWN)
			{
				printf("recv failed!\n");
				closesocket(sClient);
				WSACleanup();
				return -1;
			}
		}
		//获取当前系统时间
		SYSTEMTIME st;
		GetLocalTime(&st);
		char sDateTime[30];
		sprintf(sDateTime, "%4d-%2d-%2d%2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		//打印输出信息
		printf("%s,Recv From Client [%s:%d]:%s\n", sDateTime, inet_ntoa(remoteAddr.sin_addr), remoteAddr.sin_port, buf);

		//如果客户端发送quit字符串,则服务器退出
		if (strcmp(buf, "quit") == 0)
		{
			retval = send(sClient, "quit", strlen("quit"), 0);
			break;
		}
		else
		{
			char msg[1024];
			//sprintf(msg, "Message recvived - %s", buf);
			while (TRUE)
			{
				memset(msg, 0, 1024);
				printf("请输入聊天信息\n");
				scanf("%s", msg);
				//向服务器发送数据
				retval = send(sClient, msg, strlen(msg), 0);
				if (SOCKET_ERROR == retval)
				{
					int err = WSAGetLastError();
					printf("%d", err);
					if (err == WSAEWOULDBLOCK)		//无法立即完成非阻塞socket上的操作
					{
						Sleep(500);
						continue;
					}
					else
					{
						printf("send failed!\n");
						closesocket(sClient);
						//closesocket(sClient);
						WSACleanup();
						return -1;
					}
				}
				break;
			}



		}
	}

	closesocket(sClient);
}


事件通知管理重叠IO非阻塞式服务器

/*
* 基于重叠IO模型的Socket编程
* 重叠I/O是Win32文件操纵的一项技术,使用它可以在一个重叠结构上提交多个I/O请求,
* 并在数据传输结束后通知应用程序。在Winsock2的Socket重叠I/O模型中主要使用下面的函数。
* WSASocket()函数,用于创建Socket。
* WSASend()和WSASendTo()函数,用于发送数据
* WSAIoctl()函数,用于控制Socket模式。
* AcceptEx()函数,用于接收客户端的连接。
*/
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
#define DATA_BUFSIZE 64
int main()
{
	//---------------------------
	//声明和初始化变量

	WSABUF DataBuf;					//发送和接收数据的缓冲区结构体
	char buffer[DATA_BUFSIZE];		//缓冲区结构体DataBuf中
	DWORD EventTotal = 0,			//记录事件对象数组中的数据
		RecvBytes = 0,				//接收的字节数
		Flags = 0,					//标识位
		BytesTransferred = 0;		//在读写操作中实际传输的字节数
	//数组对象数组

	WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
	WSAOVERLAPPED AcceptOverlapped;			//重叠结构体
	SOCKET ListenSocket, AcceptSocket;		//监听socket和与客户端进行通信的socket

	//数组EventArray用于保存所有事件对象,常量WSA_MAXIMUM_WAIT_EVENTS定义时间对象句柄的最大数量
	//创建和绑定Socket,并设置其为监听状态,接受哦客户端的连接请求
	//初始化WINSOCKET

	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2), &wsaData);
	//-------------------------------
	//创建监听Socket,并将其绑定到本地IP地址和端口
	ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	u_short port = 9999;
	char* ip;
	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_port = htons(port);
	hostent* thisHost;
	thisHost = gethostbyname("");
	//ip = inet_ntoa(*(struct in_addr*)*thisHost->h_addr_list);
	
	service.sin_addr.s_addr =htonl(INADDR_ANY);
	bind(ListenSocket, (SOCKADDR*)&service, sizeof(SOCKADDR));
	//--------------------------------------
	//开始监听
	listen(ListenSocket, 1);
	printf("Listening...\n");
	//----------------------------
	//接收连接请求
	AcceptSocket = accept(ListenSocket, NULL, NULL);
	printf("Client Accepted....\n");

	//创建事件对象,并初始化重叠结构
	//调用WSACreatEvent()函数创建事件对象,并将其保存到EventArray数组中。然后对缓冲区和重叠结构AcceptOverlapped等变量进行初始化
	//创建事件对象,监理重叠结构
	EventArray[EventTotal] = WSACreateEvent();
	ZeroMemory(buffer, DATA_BUFSIZE);
	ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));			//初始化重叠结构
	AcceptOverlapped.hEvent = EventArray[EventTotal];				//设置缓冲区
	DataBuf.buf = buffer;
	EventTotal++;							//事件对象总数加1

	//-------------------------------
	//接收数据并将数据回发到客户端
	//服务器程序循环接受来自客户端的数据
	//处理在Socket上接收到数据

	while (1)
	{
		DWORD Index;				//保存处于授信状态的事件对象句柄
		//------------------------
		//调用WSARecv()函数在AcceptSocket Socket 上以重叠I/O方式接收数据,
		//保存到DataBuf缓冲区中
		if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR);
		{
			/*int err = GetLastError();
			if (WSAGetLastError() != WSA_IO_PENDING)
				printf("Error occured at WSARecv()%d\n",err);*/
		}
		//---------------------------
		//等待完成的重叠I/O调用
		Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);


		//------------------------------------
		//决定重叠事件的状态
		WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags);
		//-------------------------------------
		//如果连接已经关闭,则关闭AcceptSocket Socket
		if (BytesTransferred == 0)
		{
			printf("Closing Socket %d\n", int(AcceptSocket));
			closesocket(AcceptSocket);
			WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
			
			return -1;

		}

		//----------------------------
		//如果有数据到达,则将收到的数据则发送回客户端
		if (WSASend(AcceptSocket, &DataBuf, 1, &RecvBytes, Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
			printf("WSASend() is busted\n");

		//重置已授信的事件对象
		WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
		//----------------------------------------
		//重置Flags变量和重叠结构
		Flags = 0;
		ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
		ZeroMemory(buffer, DATA_BUFSIZE);

		AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

		//------------------------------------------------
		//重置缓冲区
		DataBuf.len = DATA_BUFSIZE;
		DataBuf.buf = buffer;
	}


}

###完成端口管理重叠IO非阻塞式服务器

/*
* 
* 使用完成例程来管理重叠IO操作
* 
* 
	@程序的工作组流程如下
	@初始化Windows Sockets环境。
	@创建监听Socket sLiten,并将其绑定到本地地址的9999端口
	@在Socket sListen上进行监听
	创建工作线程,对客户端发送来的数据进行处理。
	@循环处理来自客户端的连接请求,接受连接,并肩得到的与客户端进行通信的Socket保存到g_sNewClientConnection中。
	@将变量g_bNewConnectionArried设置位TRUE,表示存在新的客户端连接。
		
*/

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
#define DATA_BUFSIZE 64
#define PORT 9999
#define MSGSIZE 1024				//发送河接收消息的最大长度

SOCKET g_sNewClientConnection;		//接收客户端连接请求后得到的
BOOL g_bNewConnectionArrived = FALSE;			//标识是否存在未经WorkerT和read()函数处理的新的连接
//在工作线程中会使用这两个变量接收客户端发送的数据

//PER_IO_OPERATION_DATA结构体用于保存I/O操作(发送和接收数据)的数据

typedef struct
{
	WSAOVERLAPPED overlap;			//重叠结构体
	WSABUF Buffer;					//缓冲区对象
	char szMessage[MSGSIZE];		//缓冲区字符数组
	DWORD NumberOfBytesRecvd;		//接收字节数
	DWORD Flalgs;					//标识位
	SOCKET sClient;					//Socket

}PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA;

//在调用CompletinROUTINE()时,系统会自动传入重叠操作完成状态、发送的字节数、重叠操作结构体和标识位等信息.
//如果重叠操作完成状态dwError不等于0或者发送字节数cbTransferred等于0,则说明接收数据操作失败,需要关闭Socket,并释放资源
//如果接收数据成功,则调用send()函数向客户端发送接收到的数据,然后再调用WSARecv()函数继续接收来自客户端的数据

void CALLBACK CompletionROUTINE(DWORD dwError,		//重叠操作的完成状态
	DWORD cbTransferred,							//发送的字节数
	LPWSAOVERLAPPED lpOverlapped,					//指定的重叠操作结构体
	DWORD dwFlags)									//标识位
{
	//将LPWSAOVERLAPPED类型的lpOverlapped转化成了LPPER_IO_OPERATION_DATA
	LPPER_IO_OPERATION_DATA lpPerIOData = (LPPER_IO_OPERATION_DATA)lpOverlapped;
	//如果发生错误或者没有数据传输,则关闭套接字,释放资源

	if (dwError != 0 || cbTransferred == 0)
	{
		closesocket(lpPerIOData->sClient);
		HeapFree(GetProcessHeap(), 0, lpPerIOData);
	}
	else
	{
		lpPerIOData->szMessage[cbTransferred] = '\0';		//标识接收数据的结束
		//向客户端发送接收的数据
		send(lpPerIOData->sClient, lpPerIOData->szMessage, cbTransferred, 0);
		//执行另一个异步操做,接收数据
		memset(&lpPerIOData->overlap, 0, sizeof(WSAOVERLAPPED));
		lpPerIOData->Buffer.len = MSGSIZE;
		lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
		//接收数据
		WSARecv(lpPerIOData->sClient,
			&lpPerIOData->Buffer,
			1,
			&lpPerIOData->NumberOfBytesRecvd,
			&lpPerIOData->Flalgs,
			&lpPerIOData->overlap,
			CompletionROUTINE);
	}
}

//在工作线程和完成例程函数中将使用该结构体作为WSARecv()和WSASend()函数的参数

//工作线程函数WorkerThread()用于循环处理新接入的客户端连接,接收客户端数据

DWORD WINAPI WorkerThread(LPVOID lpParam)
{
	LPPER_IO_OPERATION_DATA lpPerIOData = NULL;		//保存I/O操作的数据
	while (TRUE)
	{
		if (g_bNewConnectionArrived)				//如果有新的连接请求
		{
			//为新的连接执行一个异步操作
			//为LPPER_IO_OPERATION_DATA结构体分配堆空间
			lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
				GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_OPERATION_DATA));
			//初始化结构体lpPerIOData
			lpPerIOData->Buffer.len = MSGSIZE;
			lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
			lpPerIOData->sClient = g_sNewClientConnection;
			//接收数据
			WSARecv(lpPerIOData->sClient,				//接收数据的Socket
				&lpPerIOData->Buffer					//接收数据的缓冲区
				, 1										//缓冲区的数量
				, &lpPerIOData->NumberOfBytesRecvd,		//接收数据的字节数
				&lpPerIOData->Flalgs,					//标识位
				&lpPerIOData->overlap,					//重叠结构
				CompletionROUTINE);						//完成例程函数,将会在接收数据完成的时候进行相应的调用

			g_bNewConnectionArrived = FALSE;			//标识新的连接已经处理完成


		}

		SleepEx(1000, TRUE);			//休息1秒钟,然后继续
	}

	return 0;
}



int main()
{
	
	WSADATA wsaData;			//WindowsSockets 对象
	SOCKET sListen;				//与客户端进行通信的Socket
	SOCKADDR_IN LOCAL, CLIENT;	//服务器本地地址和客户端地址
	DWORD dwThreadID;			//工作线程的线程ID
	int iaddrSize = sizeof(SOCKADDR_IN);	//地址的大小

	//初始化Windows Socket 环境
	WSAStartup(0x0202, &wsaData);
	//创建监听Socket
	sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	//绑定
	LOCAL.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	LOCAL.sin_family = AF_INET;
	LOCAL.sin_port = htons(PORT);
	bind(sListen, (struct sockaddr*)&LOCAL, sizeof(SOCKADDR_IN));

	//监听
	listen(sListen, 3);

	//创建工作线程
	CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadID);
	//循环处理来自客户端的连接请求
	while (true)
	{
	//接收连接,得到与客户端进行通信的套接字g_sNewClientConnection
		g_sNewClientConnection = accept(sListen, (struct sockaddr*)&CLIENT, &iaddrSize);

		//标识有新的连接
		g_bNewConnectionArrived = TRUE;
		//打印接入的客户端
		printf("Accepted client:%s:%d\n", inet_ntoa(CLIENT.sin_addr), ntohs(CLIENT.sin_port));
	}
	
}

c语言发送邮件

telnet链接邮件服务器步骤:https://www.cnblogs.com/blogxjc/p/10591894.html
原文链接:https://blog.youkuaiyun.com/cl18652469346/article/details/53199186/

#include<windows.h>
#include<stdio.h>
#include<WinSock.h>
#include<iostream>


using namespace std;

#pragma comment(lib,"ws2_32.lib")

struct Base64Date6
{
	unsigned int d4 : 6;
	unsigned int d3 : 6;
	unsigned int d2 : 6;
	unsigned int d1 : 6;
};

//协议中加密部分使用的是base64方法
char ConvertToBase64(char c6);
void EncodeBase64(char* dbuf, char* buf128, int len);
void SendMail(char* email,char* bodv);

int OpenSocket(struct sockaddr* addr);

int main()
{
	char EmailTo[] = "c321376@sohu.com";
	char EmailContents[] = "From: \"lucy\"<c321376@sohu.com>\r\n"
		"To: \"dasiy\"<c321376@sohu.com>\r\n"
		"Subject:Hello\r\n\r\n"
		"Hello World,Hello Email!";

	SendMail(EmailTo, EmailContents);
	return 0;
}

char ConvertToBase64(char uc)
{
	if (uc < 26)
	{
		return 'A' + uc;
	}
	if (uc < 52)
	{
		return 'a' + (uc - 26);
	}
	if (uc < 62)
	{
		return '0' + (uc - 52);
	}
	if (uc == 62)
	{
		return '+';
	}

	return '/';

}

//base64的实现
void EncodeBase64(char* dbuf, char* buf128, int len)
{
	struct Base64Date6* ddd = NULL;
	int i = 0;
	char buf[256] = { 0 };
	char* tmp = NULL;
	char cc = '\0';

	memset(buf, 0, 256);
	strcpy_s(buf, 256, buf128);

	for (i = 1; i <= len / 3; i++)
	{
		tmp = buf + (i - 1) * 3;
		cc = tmp[2];
		tmp[2] = tmp[0];
		tmp[0] = cc;
		ddd = (struct Base64Date6*)tmp;
		dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
		dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
		dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3);
		dbuf[(i - 1) * 4 + 3] = ConvertToBase64((unsigned int)ddd->d4);

	}

	if (len % 3 == 1)
	{
		tmp = buf + (i - 1) * 3;
		cc = tmp[2];
		tmp[2] = tmp[0];
		tmp[0] = cc;
		ddd = (struct Base64Date6*)tmp;
		dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
		dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
		dbuf[(i - 1) * 4 + 2] = '=';
		dbuf[(i - 1) * 4 + 3] = '=';
	}

	if (len % 3 == 2)
	{
		tmp = buf + (i - 1) * 3;
		cc = tmp[2];
		tmp[2] = tmp[0];
		tmp[0] = cc;
		ddd = (struct Base64Date6*)tmp;
		dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
		dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
		dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3);
		dbuf[(i - 1) * 4 + 3] = '=';
	}

	return;
}

//发邮件
void SendMail(char* email, char* body)
{
	int sockfd = { 0 };
	char buf[1500] = { 0 };
	char rbuf[1500] = { 0 };
	char login[128] = { 0 };
	char pass[128] = { 0 };
	WSADATA WSAData;
	struct sockaddr_in their_addr = { 0 };
	WSAStartup(MAKEWORD(2, 2), &WSAData);
	memset(&their_addr, 0, sizeof(their_addr));

	their_addr.sin_family = AF_INET;
	their_addr.sin_port = htons(25);
	hostent* hptr = gethostbyname("smtp.sohu.com");
	memcpy(&their_addr.sin_addr.S_un.S_addr, hptr->h_addr_list[0], hptr->h_length);
	printf("IP of smpt.sohu.com is : %d:%d:%d:%d\n", their_addr.sin_addr.S_un.S_un_b.s_b1,
		their_addr.sin_addr.S_un.S_un_b.s_b2,
		their_addr.sin_addr.S_un.S_un_b.s_b3,
		their_addr.sin_addr.S_un.S_un_b.s_b4);

	//连接邮件服务器,如果连接后没有响应,则2秒后重新连接
	sockfd = OpenSocket((struct sockaddr*) & their_addr);
	memset(rbuf, 0, 1500);
	while (recv(sockfd, rbuf, 1500, 0) == 0)
	{
		cout << "reconnect..." << endl;
		Sleep(2);
		sockfd = OpenSocket((struct sockaddr*)&their_addr);
		memset(rbuf, 0, 1500);
	}

	cout << rbuf << endl;

	//EHLO
	memset(buf, 0, 1500);
	sprintf_s(buf, 1500, "EHLO HYL-PC\r\n");
	send(sockfd, buf, strlen(buf), 0);

	memset(rbuf, 0, 1500);

	cout << "EHLO REceive: " << rbuf << endl;

	//AUTH LOGIN
	memset(buf, 0, 1500);
	sprintf_s(buf, 1500, "AUTH LOGIN\r\n");
	send(sockfd, buf, strlen(buf), 0);
	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);

	cout << "Auth Login Receive: " << rbuf << endl;

	//USER
	memset(buf, 0, 1500);
	sprintf_s(buf, 1500, "c321376@sohu.com");
	memset(login, 0, 128);

	EncodeBase64(login, buf, strlen(buf));
	sprintf_s(buf, 1500, "%s\r\n", login);
	send(sockfd, buf, strlen(buf), 0);

	cout << "Base64 UserName: " << buf << endl;
	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "User Login Receive: " << rbuf << endl;

	//PASSWORD
	sprintf_s(buf, 1500, "RF86TCA7DMEOUX");
	memset(pass, 0, 128);
	EncodeBase64(pass, buf, strlen(buf));
	sprintf_s(buf, 1500, "%s\r\n", pass);
	send(sockfd, buf, strlen(buf), 0);
	cout << "Base64 Password: " << buf << endl;

	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "Send Password Receive: " << rbuf << endl;

	//MAIL FROM
	memset(buf, 0, 1500);
	sprintf_s(buf, 1500, "MAIL FROM: <c321376@sohu.com>\r\n");
	send(sockfd, buf, strlen(buf), 0);

	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "set Mail From Receive: " << rbuf << endl;

	//RCPT to 第一个收件人
	sprintf_s(buf, 1500, "RCPT TO:<%s>\r\n",email);
	send(sockfd, buf, strlen(buf), 0);

	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "Tell Sendto Receive: " << rbuf << endl;

	//DATA准备开始发送邮件内容
	sprintf_s(buf, 1500, "DATA\r\n");
	send(sockfd, buf, strlen(buf), 0);
	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "Send Mail Prepare Receive: " << rbuf << endl;

	//发送邮件内容
	sprintf_s(buf, 1500, "%s\r\n.\r\n", body);
	send(sockfd, buf, strlen(buf), 0);
	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "Send Mail Receive: " << rbuf << endl;

	//QUIT
	sprintf_s(buf, 1500, "QUIT\r\n");
	send(sockfd, buf, strlen(buf), 0);
	memset(rbuf, 0, 1500);
	recv(sockfd, rbuf, 1500, 0);
	cout << "Quit Receive: " << rbuf << endl;
	//清理工作
	closesocket(sockfd);
	WSACleanup();
	return;
}

//打开TCP Socket连接
int OpenSocket(struct sockaddr* addr)
{
	int sockfd = 0;

	sockfd = socket(PF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
	{
		cout << "Open sockfd(TCP) error!" << endl;
		exit(-1);
	}
	if (connect(sockfd, addr, sizeof(struct sockaddr)) < 0)
	{
		cout << "Conncet sockfd(TCP) error!" << endl;
		exit(-1);
	}

	return sockfd;
}

在这里插入图片描述

文件传输

服务器文件代码

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

#define PORT 8087
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
#pragma comment(lib, "WS2_32")

int main()
{
 // 声明并初始化一个服务端(本地)的地址结构
 sockaddr_in server_addr;
 server_addr.sin_family = AF_INET;
 server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 server_addr.sin_port = htons(PORT);

 // 初始化socket dll
 WSADATA wsaData;
    WORD socketVersion = MAKEWORD(2, 0);
 if(WSAStartup(socketVersion, &wsaData) != 0)
 {
  printf("Init socket dll error!");
  exit(1);
 }

 // 创建socket
 SOCKET m_Socket = socket(AF_INET, SOCK_STREAM, 0);
    if (SOCKET_ERROR == m_Socket)
    {
  printf("Create Socket Error!");
  exit(1);
    }

 //绑定socket和服务端(本地)地址
 if (SOCKET_ERROR == bind(m_Socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)))
 {
  printf("Server Bind Failed: %d", WSAGetLastError());
  exit(1);
 }

 //监听
 if (SOCKET_ERROR == listen(m_Socket, 10))
 {
  printf("Server Listen Failed: %d", WSAGetLastError());
  exit(1);
 }


 while(1)
 {
  printf("Listening To Client...\n");

  sockaddr_in client_addr;
  int client_addr_len = sizeof(client_addr);

  SOCKET m_New_Socket = accept(m_Socket, (sockaddr *)&client_addr, &client_addr_len);
  if (SOCKET_ERROR == m_New_Socket)
  {
   printf("Server Accept Failed: %d", WSAGetLastError());
   break;
  }

        char buffer[BUFFER_SIZE];
        memset(buffer, 0, BUFFER_SIZE);
  if (recv(m_New_Socket, buffer, BUFFER_SIZE, 0) < 0)
  {
   printf("Server Receive Data Failed!");
   break;
  }

  char file_name[FILE_NAME_MAX_SIZE+1];
  memset(file_name, 0, FILE_NAME_MAX_SIZE+1);
  strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE:strlen(buffer));
        printf("%s\n", file_name);

  FILE * fp = fopen(file_name, "rb");  //windows下是"rb",表示打开一个只读的二进制文件
  if (NULL == fp)
  {
   printf("File: %s Not Found\n", file_name);
  }
        else
  {
   memset(buffer, 0, BUFFER_SIZE);
   int length = 0;

   while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
   {
    if (send(m_New_Socket, buffer, length, 0) < 0)
    {
     printf("Send File: %s Failed\n", file_name);
     break;
    }
    memset(buffer, 0, BUFFER_SIZE);
   }

   fclose(fp);
   printf("File: %s Transfer Successful!\n", file_name);
  }
  closesocket(m_New_Socket);
 }

 closesocket(m_Socket);
 //释放winsock库
 WSACleanup();
 return 0;
} 

客户端文件代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<WINSOCK2.H>


#define PORT 8087
#define SERVER_IP "192.168.108.141"
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
#pragma comment(lib,"Ws2_32")

int main()
{
	WSADATA wsaData;
	WORD socketVersion=MAKEWORD(2,2);
	if(WSAStartup(socketVersion,&wsaData)!=0)
	{
		printf("Init socket dll error!");
		exit(1);
	}

	//创建socket
	SOCKET c_Socket=socket(AF_INET,SOCK_STREAM,0);
	if(SOCKET_ERROR==c_Socket)
	{

		printf("Create Socket Error!");
		system("pause");
		exit(1);
	}

	//指定服务端地址
	sockaddr_in server_addr;
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.S_un.S_addr=inet_addr(SERVER_IP);
	server_addr.sin_port=htons(PORT);

	if(SOCKET_ERROR==connect(c_Socket,(LPSOCKADDR)&server_addr,sizeof(server_addr)))
	{
		printf("Can Not Connect To Server IP!\n");
		system("pause");
		exit(1);

	}

	//输入文件名

	char file_name[FILE_NAME_MAX_SIZE+1];
	memset(file_name,0,FILE_NAME_MAX_SIZE+1);
	printf("please Input File Name On Server:");
	scanf("%s",&file_name);

	char buffer[BUFFER_SIZE];
 	memset(buffer,0,BUFFER_SIZE);
	strncpy(buffer,file_name,strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));

	//向服务器发送文件名
	if(send(c_Socket,buffer,BUFFER_SIZE,0)<0)
	{
		printf("Send File Name Failed\n");
		printf("send  %d", WSAGetLastError());
		system("pause");
		exit(1);
	}
	//string fname="d:\234.txt";

	//打开文件,准备写入
	FILE *fp=fopen(file_name,"w");
	if(NULL==fp)
	{
		printf("File:%s Can Not Open To Write\n",file_name);
		printf("file open %d", WSAGetLastError());

		system("pause");
		exit(1);
	}
	else
	{
		memset(buffer,0,BUFFER_SIZE);
		int length=0;
		while((length=recv(c_Socket,buffer,BUFFER_SIZE,0))>0)
		{
			if(fwrite(buffer,sizeof(char),length,fp)<length)
			{
				printf("File:%s Write Failed\n",file_name);
				break;
			}

			memset(buffer,0,BUFFER_SIZE);
		}

		printf("Receive File: %s From Server Successful!\n",file_name);

	}

	fclose(fp);

	closesocket(c_Socket);
	//释放winsock 库
	WSACleanup();
	system("pause");
	return 0;
}
###FD_SET宏介绍
#include<WinSock2.h>
#include<stdio.h>
#pragma comment(lib,"WS2_32.lib")
#define PORT 8888
int main()
{
	FD_SET ReadSet,WriteSet;
	FD_ZERO(&ReadSet);
	FD_ZERO(&WriteSet);
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);		//初始化
	SOCKET ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);	//定义一个监听套接字
	SOCKADDR_IN InternetAddr;    //服务器地址

	//设置监听地址和端口
	InternetAddr.sin_family = AF_INET;
	InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	InternetAddr.sin_port = htons(PORT);

	bind(ListenSocket, (sockaddr*)&InternetAddr, sizeof(sockaddr));
	FD_SET(ListenSocket, &ReadSet);		//将套接字加入ReadSet集合中
	FD_SET(1, &ReadSet);

	FD_SET(1, &WriteSet);
	FD_SET(1, &ReadSet);
	FD_SET(2, &ReadSet);
	FD_SET(3, &ReadSet);
	FD_SET(4, &ReadSet);
	FD_SET(5, &ReadSet);
	int isset = FD_ISSET(1, &ReadSet);
	printf("isset = %d\n", isset);
	FD_CLR(1, &ReadSet);
	FD_CLR(2, &ReadSet);
	FD_CLR(3, &ReadSet);
	isset = FD_ISSET(3, &ReadSet);
	printf("isset = %d\n", isset);
	isset = FD_ISSET(ListenSocket, &ReadSet);
	printf("Before select,isset=%d\n", isset);		//所以这里打印结果为1

	struct timeval tTime;
	tTime.tv_sec = 10;
	tTime.tv_usec = 0;
	select(0, &ReadSet, &WriteSet, NULL, &tTime);		//通过SELECT筛选处于就绪状态的FD
	//这时,刚才的LisetenSocket并不在就绪状态(没有连接连入),那么就从ReadSet中去除他,但在实际调试中FD还在队列中
	isset = FD_ISSET(ListenSocket, &ReadSet);
	printf("After select,isset=%d \n",isset);		//所以这里打印的结果为0

	system("pause");

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值