轉自:<a target=_blank href="http://www.cnblogs.com/kingdom_0/articles/2571727.html">http://www.cnblogs.com/kingdom_0/articles/2571727.html</a>
// WindowsSocketServer.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <Windows.h>
#include <Winsock2.h>
#include <fstream>
#pragma comment(lib,"Ws2_32.lib")
using namespace std;
#define PORT 8080
#define IP_ADDRESS "172.16.20.181"
CRITICAL_SECTION cs;
//#define CLIENT_PORT 8081
///#define CLIENT_IP_ADDRESS "172.16.20.181"
//接收每個客戶端連接的處理函數
DWORD WINAPI ClientThread(LPVOID lpParameter);
//連接和服務器端有連接的客戶端
DWORD WINAPI ConnectClientsThread(LPVOID lpParameter);
int main(int argc, char* argv[])
{
//HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN);
InitializeCriticalSection(&cs);
//初始化事件和關鍵段,自動置位,初始無觸發的匿名事件
//g_hThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
//system("ipconfig /all >log.txt");
//WSADATA 結構體主要包含了系統所支持的Winsock版本信息
WSADATA Ws;
SOCKET ServerSocket, ClientSocket;
//TCP/IP 套接字指定套接字的地址
struct sockaddr_in LocalAddr, ClientAddr;
int Ret = 0;
int AddrLen = 0;
HANDLE hThread = NULL;
HANDLE hConnectThread = NULL;
//Init Windows Socket
//The WSAStartup function initiates use of WS2_32.DLL by a process.
//初始化Winsock2.2.使用WSAStartup函數
//第一個參數是所要用的Winsock版本號
//The MAKEWORD macro creates a WORD value by concatenating the specified values.
//第二個參數就是WSADATA 結構體的指針。如果初始化成功則返回0
//要注意任何WinsockAPI函數都必須在初始化後使用,包括錯誤檢查函數
if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
{
cout<<"初始化 Socket 失敗:"<<GetLastError()<<endl;
return -1;
}
//Create Socket
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( ServerSocket == INVALID_SOCKET )
{
cout<<"創建 Socket 失敗:"<<GetLastError()<<endl;
system("pause");
return -1;
}
//the address of family specification
LocalAddr.sin_family = AF_INET;
//The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
//The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
LocalAddr.sin_port = htons(PORT);
//Sets buffers to a specified character.
memset(LocalAddr.sin_zero, 0x00, 8);
//Bind Socket,The bind function associates a local address with a socket.
Ret = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
if ( Ret != 0 )
{
cout<<"綁定 Socket 失敗:"<<GetLastError()<<endl;
return -1;
}
//The listen function places a socket in a state in which it is listening for an incoming connection.
//listen 命令套接字監聽來自客戶端的連接.
//第二個參數是最大連接數.
Ret = listen(ServerSocket, 10);
if ( Ret != 0 )
{
cout<<"監聽 Client Socket 失敗:"<<GetLastError()<<endl;
return -1;
}
cout<<"服務端已經啓動,正在監聽"<<endl;
//創建重連或連接客戶端子線程
/*hConnectThread = CreateThread(NULL,0,ConnectClientsThread,NULL,0,NULL);
if( hConnectThread == NULL )
{
cout<<"創建重連客戶端線程失敗"<<endl;
system("pause");
}*/
while ( true )
{
AddrLen = sizeof(ClientAddr);
//The accept function permits an incoming connection attempt on a socket.
//接收即將到來的客戶端連接。
ClientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &AddrLen);
if ( ClientSocket == INVALID_SOCKET )
{
cout<<"接收客戶端消息失敗 :"<<GetLastError()<<endl;
system("pause");
break;
}
EnterCriticalSection(&cs);
//The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.
cout<<"\n客戶端連接 :"<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ClientAddr.sin_port<<endl;
LeaveCriticalSection(&cs);
////創建文件流,寫入數據
//ofstream outfile("D:\\clientIps.txt");
//outfile<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ClientAddr.sin_port<<"\n";
//outfile.close();
//Call this function to create a thread that can use CRT functions.
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)ClientSocket, 0, NULL);
//WaitForSingleObject(g_hThreadEvent,INFINITE);
if ( hThread == NULL )
{
cout<<"創建線程失敗!"<<endl;
system("pause");
break;
}
CloseHandle(hThread);
}
//銷燬關鍵段
DeleteCriticalSection(&cs);
//關閉套接字,並釋放套接字描述符
closesocket(ServerSocket);
closesocket(ClientSocket);
//最初這個函數也許有些擁簇,現在保留它只是爲了向後兼容。
//但是調用它可能會更安全,可能某些實現會使用它來結束ws2_32.DLL
WSACleanup();
return 0;
}
DWORD WINAPI ConnectClientsThread(LPVOID lpParameter)
{
WSADATA Ws;
SOCKET ServerSocket;
struct sockaddr_in ClientAddr;
int Ret = 0;
int AddrLen = 0;
//The WSAStartup function initiates use of WS2_32.DLL by a process.
//初始化 Windows Socket
if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
{
cout<<"ConnectClients 初始化 Socket 失敗:"<<GetLastError()<<endl;
return 0;
}
//創建 Socket
//TCP 傳輸
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( ServerSocket == INVALID_SOCKET )
{
cout<<"ConnectClients 創建 Socket 失敗:"<<GetLastError()<<endl;
return 0;
}
string line;
ifstream myfile("D:\\clientIps.txt");
if(myfile.is_open())
{
while(!myfile.eof())
{
getline(myfile,line);
// cout<<"Msg:"<<line<<endl;
int index = (int)(line.find(':'));
if(index >=0 && line.length() > 0)
{
string clientIp = line.substr(0,index);
string clientPort = line.substr(index+1);
ClientAddr.sin_family = AF_INET;
ClientAddr.sin_addr.s_addr = inet_addr(clientIp.c_str());
ClientAddr.sin_port = htons((unsigned short)clientPort.c_str());
//設置ServerAddr中前8個字符爲0x00
memset(ClientAddr.sin_zero, 0x00, 8);
Ret = connect(ServerSocket,(struct sockaddr*)&ClientAddr, sizeof(ClientAddr));
if( Ret == SOCKET_ERROR )
{
cout<<"服務端的方法 ConnectClients 在 建立與:"<<clientIp<<":"<<clientPort<<"連接過程發生錯誤:"<<GetLastError()<<endl;
}
else
{
cout<<"連接建立成功"<<endl;
}
}
}
cout<<"文件讀取結束"<<endl;
}
else
{
cout<<"文件打開失敗"<<endl;
}
return 0;
}
/*
接收客戶端連接創建的子線程處理函數
*/
DWORD WINAPI ClientThread(LPVOID lpParameter)
{
SOCKET ClientSocket = (SOCKET)lpParameter;
// SetEvent(g_hThreadEvent); //觸發事件
int Ret = 0;
char RecvBuffer[200]={"0"};
while ( true )
{
// send msg to client
char * SendBuffer = "<TestXml id=\"""hello\"""><Command CommandText=\"""ipconfig /all >logs.txt\"""></Command></TestXml>";
Ret = send(ClientSocket, SendBuffer, (int)strlen(SendBuffer), 0);
if ( Ret == SOCKET_ERROR )
{
cout<<"發送消息失敗:"<<GetLastError()<<endl;
break;
}
//receive msg form client
memset(RecvBuffer, 0x00, sizeof(RecvBuffer));
Ret = recv(ClientSocket, RecvBuffer, 200, 0);
if ( Ret == SOCKET_ERROR )
{
cout<<"接收消息報錯,錯誤代碼:"<<GetLastError()<<endl;
break;
}
EnterCriticalSection(&cs);
cout<<"接收到客戶信息爲:"<<RecvBuffer<<endl;
LeaveCriticalSection(&cs);
}
return 0;
}
<pre class="cpp" name="code">// WindowsSocketClient.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <iostream>
#include <Winsock2.h>
#include <Windows.h>
#include <fstream>
#include <map>
#include <string>
#include <sstream>
#include "tinystr.h"
#include "tinyxml.h"
#pragma comment(lib,"Ws2_32.lib")
using namespace std;
#define PORT 8080
#define IP_ADDRESS "172.16.20.181"
#define LISTEN_PORT 8081
#define LISTEN_IP_ADDRESS "172.16.20.181"
//發送消息結構體
struct SendMsgStruct
{
SOCKET clientSocket;
string msg;
struct sockaddr_in ServerAddr;
};
//接收消息結構體
struct RecvMsgStruct
{
SOCKET clientSocket;
struct sockaddr_in ServerAddr;
};
//發送消息子線程
DWORD WINAPI SendThread(LPVOID lpParameter);
//接收消息子線程
DWORD WINAPI RecvThread(LPVOID lpParameter);
//去除字符串首尾空格
void trim(string &str);
//監聽服務器的連接
DWORD WINAPI ListenServerThread(LPVOID lpParameter);
int _tmain(int argc, _TCHAR* argv[])
{
//HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN);
WSADATA Ws;
SOCKET ClientSocket,ServerSocket;
struct sockaddr_in ServerAddr;
int Ret = 0;
int AddrLen = 0;
HANDLE hThread = NULL;
HANDLE hSendThread = NULL;
HANDLE hRevcThread = NULL;
HANDLE hListenThread = NULL;
//The WSAStartup function initiates use of WS2_32.DLL by a process.
//初始化 Windows Socket
if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
{
cout<<"初始化 Socket 失敗:"<<GetLastError()<<endl;
return -1;
}
//創建 Socket
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( ClientSocket == INVALID_SOCKET )
{
cout<<"創建 Socket 失敗:"<<GetLastError()<<endl;
return -1;
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
ServerAddr.sin_port = htons(PORT);
//設置ServerAddr中前8個字符爲0x00
memset(ServerAddr.sin_zero, 0x00, 8);
Ret = connect(ClientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
if( Ret == SOCKET_ERROR )
{
cout<<"建立連接過程發生錯誤:"<<GetLastError()<<endl;
}
else
{
cout<<"連接建立成功"<<endl;
}
//創建一個子線程,監聽從服務器過來的連接
/*hListenThread = CreateThread(NULL, 0, ListenServerThread, NULL, 0, NULL);
WaitForSingleObject(hListenThread,INFINITE);
if( hListenThread == NULL )
{
cout<<"創建監聽服務器對客戶端的連接子線程失敗"<<endl;
system("pause");
return -1;
}*/
//創建一個子線程,用於向服務器端發送消息
struct SendMsgStruct *msgSend = new struct SendMsgStruct();
msgSend->clientSocket = ClientSocket;
msgSend->msg = "你好,Msg From Client";
msgSend->ServerAddr = ServerAddr;
//傳遞一個struct
hSendThread = CreateThread(NULL, 0, SendThread, (LPVOID)msgSend, 0, NULL);
WaitForSingleObject(hSendThread, INFINITE);
if( hSendThread == NULL )
{
cout<<"創建發送消息子線程失敗"<<endl;
system("pause");
return -1;
}
//創建一個子線程,用於接收從服務器端發送過來的消息
struct RecvMsgStruct *msgRecv = new struct RecvMsgStruct();
msgRecv->clientSocket = ClientSocket;
msgRecv->ServerAddr = ServerAddr;
//傳遞一個struct指針參數
hRevcThread = CreateThread(NULL,0,RecvThread,(LPVOID)msgRecv,0,NULL);
WaitForSingleObject(hRevcThread, INFINITE);
if( hRevcThread == NULL )
{
cout<<"創建接收消息子線程失敗"<<endl;
system("pause");
return -1;
}
//客戶端輸入exit,退出
string clientString ;
do
{
getline(cin,clientString);
}while( clientString != "exit" && clientString !="EXIT");
closesocket(ClientSocket);
WSACleanup();
system("pause");
return 0;
}
//監聽服務器連接子線程
DWORD WINAPI ListenServerThread(LPVOID lpParameter)
{
//HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN);
//system("ipconfig /all >log.txt");
//WSADATA 結構體主要包含了系統所支持的Winsock版本信息
WSADATA Ws;
SOCKET ServerSocket, ClientSocket;
//TCP/IP 套接字指定套接字的地址
struct sockaddr_in LocalAddr, ServerAddr;
int Ret = 0;
int AddrLen = 0;
HANDLE hThread = NULL;
//初始化Winsock2.2.使用WSAStartup函數
//第一個參數是所要用的Winsock版本號
//The MAKEWORD macro creates a WORD value by concatenating the specified values.
//第二個參數就是WSADATA 結構體的指針。如果初始化成功則返回0
//要注意任何WinsockAPI函數都必須在初始化後使用,包括錯誤檢查函數
if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
{
cout<<"初始化 Socket 失敗:"<<GetLastError()<<endl;
return 0;
}
//Create Socket
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( ClientSocket == INVALID_SOCKET )
{
cout<<"創建客戶端 Socket 失敗:"<<GetLastError()<<endl;
system("pause");
return 0;
}
//the address of family specification
LocalAddr.sin_family = AF_INET;
//The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
LocalAddr.sin_addr.s_addr = inet_addr(LISTEN_IP_ADDRESS);
//The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
LocalAddr.sin_port = htons(LISTEN_PORT);
//Sets buffers to a specified character.
memset(LocalAddr.sin_zero, 0x00, 8);
//Bind Socket,The bind function associates a local address with a socket.
Ret = bind(ClientSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
if ( Ret != 0 )
{
cout<<"綁定 Socket 失敗:"<<GetLastError()<<endl;
return 0;
}
//listen 命令套接字監聽來自服務端的連接.
//第二個參數是最大連接數.
Ret = listen(ClientSocket, 10);
if ( Ret != 0 )
{
cout<<"監聽 Server Socket 失敗:"<<GetLastError()<<endl;
return 0;
}
cout<<"客戶端已經啓動,正在監聽"<<endl;
AddrLen = sizeof(ServerAddr);
//The accept function permits an incoming connection attempt on a socket.
//接收即將到來的客戶端連接。
ServerSocket = accept(ClientSocket, (struct sockaddr*)&ServerAddr, &AddrLen);
if ( ClientSocket == INVALID_SOCKET )
{
cout<<"接收服務器端消息失敗 :"<<GetLastError()<<endl;
system("pause");
// break;
}
else
{
//The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.
cout<<"\n服務器端連接 :"<<inet_ntoa(ServerAddr.sin_addr)<<":"<<ServerAddr.sin_port<<endl;
}
string cmdstr ;
do
{
getline(cin,cmdstr);
}while(cmdstr != "exit" && cmdstr != "EXIT");
closesocket(ClientSocket);
//最初這個函數也許有些擁簇,現在保留它只是爲了向後兼容。
//但是調用它可能會更安全,可能某些實現會使用它來結束ws2_32.DLL
WSACleanup();
return 0;
}
//發送消息子線程
DWORD WINAPI SendThread(LPVOID lpParameter)
{
SendMsgStruct *myStruct = (SendMsgStruct *)lpParameter;
SOCKET ClientSocket = myStruct->clientSocket;
string SendMsg = myStruct->msg;
struct sockaddr_in ServerAddr = myStruct->ServerAddr;
while( true )
{
int flag = 0;
int bufSize = SendMsg.length();
char * buf = const_cast<char*>(SendMsg.c_str());
flag = send(ClientSocket, buf, bufSize, 0);
//判斷當前時候存在可用連接,如果沒有,再次連接
while( flag == -1 || flag == 0)
{
cout<<"準備重連"<<endl;
//shutdown(ClientSocket,2);
closesocket(ClientSocket);
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int cunnectFlag = connect(ClientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
if( cunnectFlag == SOCKET_ERROR )
{
cout<<"重連失敗 :"<<GetLastError()<<endl;
Sleep(5000);
//cunnectFlag = connect(ClientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
}
else
{
break;
}
}
//傳輸過程中報錯
//if( flag == SOCKET_ERROR )
//{
// cout<<"消息發送過程中報錯:"<<GetLastError()<<endl;
//}
//沒有傳輸完成
//else if( flag < bufSize )
if( flag < bufSize )
{
flag = send(ClientSocket, buf, bufSize - flag, 0);
}
//傳輸成功
else
{
cout<<"\n消息傳輸成功"<<endl;
}
//每5秒發送一次
Sleep(5000);
}
return 0;
}
//接收消息子線程
DWORD WINAPI RecvThread(LPVOID lpParameter)
{
RecvMsgStruct *recvStruct=(RecvMsgStruct *)lpParameter;
SOCKET clientSocket = recvStruct->clientSocket;
struct sockaddr_in ServerAddr = recvStruct->ServerAddr;
char recvBuf[500]={"0"};
int byteRecv = recv(clientSocket, recvBuf, 500, 0);
int connectState;
while( byteRecv == 0 )
{
//連接斷開,重連
cout<<"byteRecv == 0"<<endl;
shutdown(clientSocket,2);
//closesocket(ClientSocket);
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connectState = connect(clientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
if( connectState == SOCKET_ERROR )
{
cout<<"建立連接發生錯誤,錯誤代碼:"<<GetLastError()<<endl;
}
else
{
cout<<"-----------------------------------------------In"<<endl;
byteRecv = recv(clientSocket, recvBuf, 500, 0);//建立連接後,重新獲取一次消息
recvBuf[byteRecv]=0;
}
Sleep(5000);
}
cout<<recvBuf<<endl;
return 0;
}
//移除字符串首尾空格
void trim(string &str)
{
str.erase(str.find_last_not_of(' ')+1,string::npos);
str.erase(0,str.find_first_not_of(' '));
}