windows网络编程【003】实现简单WSASocket的C/S结构-_-!~~~~~~
运行时,请先启动服务器端
/**/
/*
* 服务器端
*/
#include < Winsock2.h >
#include < stdio.h >
#include < iostream.h >
#pragma comment(lib, " Ws2_32.lib " )
SOCKET sockSvc; // 服务器端socket
SOCKET sockConnect; // 连接用的socket
DWORD WINAPI RecvData(LPVOID lpParameter); // 接收线程的函数
int main()
{
WORD wVersionRequested;//定义socket1.1或者socket2.0
WSADATA wsaData; //定义装载socket版本的变量
int err; //错误变量
wVersionRequested = MAKEWORD(2,2); //定义连接为socket2.0
err = WSAStartup(wVersionRequested, &wsaData); //装载socket2.0支持
if(0 != err)//判断是否装载成功
{
return -1;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)//判断版本号,是否和定义的一样
{
WSACleanup(); //若出问题,卸载支持,并结束程序返回-1
return -1;
}
sockSvc = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
/**//*
SOCKET WSASocket(int af, int type, int protocol,
LPWSAPROTOCOL_INFO lpprotocolinfo,
GROUP g, DWORD dwflags)
SOCKET socket(int af, int type, int protocol)
参数:地址族,套接字类型和协议类型
这三个因素共同决定了创建套接字的服务提供者
传输服务提供者实现的功能包括建立连接,传输数据,实现流控制和差错控制等函数。
Ws2_32.dll在应用程序和服务提供者之间实现了媒介的功能
第一
socket()和WSASocket()函数都能返回一个SOCKET套接字;
socket()主要实现同步传输,Socket库中例程在应用于阻塞套接口时会阻塞。
WSASocket()用于异步传输,WSASocket()的发送操作和接收操作都可以被重叠使用。
WSASocket()的接收函数可以被多次调用,发出接收缓冲区,准备接收到来的数据。
发送函数也可以被多次调用,组成一个发送缓冲区队列。
socket()却只能发过之后等待回消息才可做下一步操作!
其次
WSASocket()所支持的版本如下:
Version: Requires Windows Sockets2.0.
Header: Declared in Winsock2.h.
socket()所支持老一些的版本,如Windows Sockets1.0和
Version: Requires Windows Sockets1.1
*/
SOCKADDR_IN addrSvc; //服务器地址信息
addrSvc.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //0 接收所有数据包
addrSvc.sin_family = AF_INET;
addrSvc.sin_port = htons(4000);//监听 端口
bind(sockSvc,(SOCKADDR*)&addrSvc,sizeof(SOCKADDR)); //绑定服务和端口
listen(sockSvc,50);
/**//*
int listen(SOCKET s, int users);
服务程序可以调用listen函数使其流套接字s处于监听状态。处于监听状态的流套接字s将维
护一个客户连接请求队列,该队列最多容纳users个客户连接请求。假如该函数执行成功,
则返回0;如果执行失败,则返回SOCKET_ERROR。
*/
SOCKADDR_IN addrClient;
int length = sizeof(SOCKADDR);
while(1)
{
sockConnect = accept(sockSvc, (SOCKADDR*)&addrClient,&length);
/**//*
SOCKET accept(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
);
服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,
并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,
以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一个参数
指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用
第三个参数来返回新创建的套接字的地址结构的长度。
*/
if(INVALID_SOCKET != sockConnect)
{
HANDLE hThread;
hThread=CreateThread(NULL,0,RecvData,(LPVOID)sockConnect,0,NULL);
/**//*
/*
我们得定义一个句柄用来存放它的返回值。还定义一个指向线程ID的DWORD值dwThreadId。
CreateThread函数有六个参数分别是
LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes
DWORD dwStackSize, // initial thread stack size
LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function
LPVOID lpParameter, //argument for new thread
DWORD dwCreationFlags, // creation flags
LPDWORD lpThreadId // pointer to receive thread ID
中第一个参数我们设置为NULL,使这个句柄不能被继承;第二个参数设置为0,使用默认的堆栈
大小;第三个参数为线程函数的起始地址,也就是线程函数的函数名;第四个参数要传递给线程
函数的值;第五个参数为0,创建好之后马上让线程运行;第六个参数设置为指向线程ID的地址。
严格来说这里需要加错误检测if(NULL == hThead){}
*/
CloseHandle(hThread);
}
}
Sleep(INFINITE);
closesocket(sockConnect);
WSACleanup(); // 严格来说这里需要加错误检测if(0 != WSACleanup()){}
}
DWORD WINAPI RecvData(LPVOID lpParameter) // 线程接收函数
{
SOCKET socket = (unsigned int)lpParameter;
char recvBuffer[1024];
for(;;)
{
//receive data from client
if(SOCKET_ERROR == recv(socket, recvBuffer, 1024, 0)) //和客户端的send相对应
{
cout<<"The receive data defeat or was the client side already withdraws\n"<<endl;
break;
}
cout<<"Client says: "<<recvBuffer<<endl;
}
closesocket(socket); // 严格来说这里需要加错误检测if(0 != closesocket(socket)){}
return 0;
}
* 服务器端
*/
#include < Winsock2.h >
#include < stdio.h >
#include < iostream.h >
#pragma comment(lib, " Ws2_32.lib " )
SOCKET sockSvc; // 服务器端socket
SOCKET sockConnect; // 连接用的socket
DWORD WINAPI RecvData(LPVOID lpParameter); // 接收线程的函数
int main()
{
WORD wVersionRequested;//定义socket1.1或者socket2.0
WSADATA wsaData; //定义装载socket版本的变量
int err; //错误变量
wVersionRequested = MAKEWORD(2,2); //定义连接为socket2.0
err = WSAStartup(wVersionRequested, &wsaData); //装载socket2.0支持
if(0 != err)//判断是否装载成功
{
return -1;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)//判断版本号,是否和定义的一样
{
WSACleanup(); //若出问题,卸载支持,并结束程序返回-1
return -1;
}
sockSvc = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
/**//*
SOCKET WSASocket(int af, int type, int protocol,
LPWSAPROTOCOL_INFO lpprotocolinfo,
GROUP g, DWORD dwflags)
SOCKET socket(int af, int type, int protocol)
参数:地址族,套接字类型和协议类型
这三个因素共同决定了创建套接字的服务提供者
传输服务提供者实现的功能包括建立连接,传输数据,实现流控制和差错控制等函数。
Ws2_32.dll在应用程序和服务提供者之间实现了媒介的功能
第一
socket()和WSASocket()函数都能返回一个SOCKET套接字;
socket()主要实现同步传输,Socket库中例程在应用于阻塞套接口时会阻塞。
WSASocket()用于异步传输,WSASocket()的发送操作和接收操作都可以被重叠使用。
WSASocket()的接收函数可以被多次调用,发出接收缓冲区,准备接收到来的数据。
发送函数也可以被多次调用,组成一个发送缓冲区队列。
socket()却只能发过之后等待回消息才可做下一步操作!
其次
WSASocket()所支持的版本如下:
Version: Requires Windows Sockets2.0.
Header: Declared in Winsock2.h.
socket()所支持老一些的版本,如Windows Sockets1.0和
Version: Requires Windows Sockets1.1
*/
SOCKADDR_IN addrSvc; //服务器地址信息
addrSvc.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //0 接收所有数据包
addrSvc.sin_family = AF_INET;
addrSvc.sin_port = htons(4000);//监听 端口
bind(sockSvc,(SOCKADDR*)&addrSvc,sizeof(SOCKADDR)); //绑定服务和端口
listen(sockSvc,50);
/**//*
int listen(SOCKET s, int users);
服务程序可以调用listen函数使其流套接字s处于监听状态。处于监听状态的流套接字s将维
护一个客户连接请求队列,该队列最多容纳users个客户连接请求。假如该函数执行成功,
则返回0;如果执行失败,则返回SOCKET_ERROR。
*/
SOCKADDR_IN addrClient;
int length = sizeof(SOCKADDR);
while(1)
{
sockConnect = accept(sockSvc, (SOCKADDR*)&addrClient,&length);
/**//*
SOCKET accept(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
);
服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,
并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,
以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一个参数
指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用
第三个参数来返回新创建的套接字的地址结构的长度。
*/
if(INVALID_SOCKET != sockConnect)
{
HANDLE hThread;
hThread=CreateThread(NULL,0,RecvData,(LPVOID)sockConnect,0,NULL);
/**//*
/*
我们得定义一个句柄用来存放它的返回值。还定义一个指向线程ID的DWORD值dwThreadId。
CreateThread函数有六个参数分别是
LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes
DWORD dwStackSize, // initial thread stack size
LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function
LPVOID lpParameter, //argument for new thread
DWORD dwCreationFlags, // creation flags
LPDWORD lpThreadId // pointer to receive thread ID
中第一个参数我们设置为NULL,使这个句柄不能被继承;第二个参数设置为0,使用默认的堆栈
大小;第三个参数为线程函数的起始地址,也就是线程函数的函数名;第四个参数要传递给线程
函数的值;第五个参数为0,创建好之后马上让线程运行;第六个参数设置为指向线程ID的地址。
严格来说这里需要加错误检测if(NULL == hThead){}
*/
CloseHandle(hThread);
}
}
Sleep(INFINITE);
closesocket(sockConnect);
WSACleanup(); // 严格来说这里需要加错误检测if(0 != WSACleanup()){}
}
DWORD WINAPI RecvData(LPVOID lpParameter) // 线程接收函数
{
SOCKET socket = (unsigned int)lpParameter;
char recvBuffer[1024];
for(;;)
{
//receive data from client
if(SOCKET_ERROR == recv(socket, recvBuffer, 1024, 0)) //和客户端的send相对应
{
cout<<"The receive data defeat or was the client side already withdraws\n"<<endl;
break;
}
cout<<"Client says: "<<recvBuffer<<endl;
}
closesocket(socket); // 严格来说这里需要加错误检测if(0 != closesocket(socket)){}
return 0;
}
/**/
/*
* 客户端
*/
#include < Winsock2.h >
#include < stdio.h >
#pragma comment(lib, " Ws2_32.lib " )
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if(err != 0){
return;
}
if(LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2 ){
WSACleanup();
return;
}
SOCKET sockClient = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
SOCKADDR_IN addrClient; //服务器地址信息
addrClient.sin_addr.S_un.S_addr = inet_addr("192.168.94.37"); //要连接的服务地址
addrClient.sin_family = AF_INET; //协议族
addrClient.sin_port = htons(4000); //请求的端口
char sendBuffer[1024]; //每次发送的最大数据量
connect(sockClient, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));//连接服务器端
while(true)
{
/**//*send data to service*/
printf("Please input data:\n");
if(gets(sendBuffer) == NULL) //输入要发送的数据
break;
else
{
if(SOCKET_ERROR == send(sockClient,sendBuffer,
strlen(sendBuffer)+1,0)) //TCP方式发送
{
printf("Transmission data defeat!\n");
break;
}
}
}
closesocket(sockClient); // 严格来说这里需要加错误检测if(0 != closesocket(socket)){}
WSACleanup();
}
* 客户端
*/
#include < Winsock2.h >
#include < stdio.h >
#pragma comment(lib, " Ws2_32.lib " )
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if(err != 0){
return;
}
if(LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2 ){
WSACleanup();
return;
}
SOCKET sockClient = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
SOCKADDR_IN addrClient; //服务器地址信息
addrClient.sin_addr.S_un.S_addr = inet_addr("192.168.94.37"); //要连接的服务地址
addrClient.sin_family = AF_INET; //协议族
addrClient.sin_port = htons(4000); //请求的端口
char sendBuffer[1024]; //每次发送的最大数据量
connect(sockClient, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));//连接服务器端
while(true)
{
/**//*send data to service*/
printf("Please input data:\n");
if(gets(sendBuffer) == NULL) //输入要发送的数据
break;
else
{
if(SOCKET_ERROR == send(sockClient,sendBuffer,
strlen(sendBuffer)+1,0)) //TCP方式发送
{
printf("Transmission data defeat!\n");
break;
}
}
}
closesocket(sockClient); // 严格来说这里需要加错误检测if(0 != closesocket(socket)){}
WSACleanup();
}
地震让大伙知道:居安思危,才是生存之道。