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;
}