随便写写,非常简单,可以作为网络通信入门代码。
代码分为两部分:一个服务端;一个客户端。分别建立两个工程,直接编译运行就可以见到效果!
其中用到了多线程的一些技术,关于线程同步这方面暂未考虑!
/************************************************************************/
/*Server.cpp */
/************************************************************************/
#include <WinSock2.h>
#include <iostream>
#include <string>
#include <process.h>
#include <list>
//using namespace std;
//#pragma comment (lib, "wsock32.lib") //或者 连接器-》输入-》附加依赖项中加入wsock32.lib
#pragma comment (lib, "WS2_32.lib")
#define MAXBUF 32767
int nFlag = 1; //0表示退出
std::list<SOCKET> ConnSocketLst;
SOCKET ListeningSocket;
//接受数据
UINT WINAPI RecvData(LPVOID pParam);
//发送数据
UINT WINAPI SendData(LPVOID pParam);
int main()
{
WSADATA WsaData;
//SOCKET ListeningSocket;
//SOCKET NewConnectSocket;
SOCKADDR_IN ServerAddr;
SOCKADDR_IN ClientAddr;
int Port = 5678;
//初始化版本2.2
if (0 != WSAStartup(MAKEWORD(2, 2), &WsaData))
{
std::cout << "网络初始化失败\n";
getchar();
return -1;
}
//创建一个新的套接字来监听客户机的连接
ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//建立一个SOCKADDR_IN结构,来告知bind函数要在5678端口上监听所有接口的连接
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port); //主机字节顺序转换为网络字节顺序
ServerAddr.sin_addr.s_addr = htonl(ADDR_ANY);
//使用bind函数将这个地址信息与套接字关联起来
bind(ListeningSocket, (SOCKADDR*)&ServerAddr, sizeof(SOCKADDR));
//监听客户机
listen(ListeningSocket, 5);
//得到尺寸
int ClientLen = sizeof(SOCKADDR_IN);
//创建线程,发送数据
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, SendData, NULL, 0, NULL);
//循环得到客户端的连接
while(0 != nFlag)
{
//连接到达时接受一个新连接
SOCKET NewConnectSocket = accept(ListeningSocket, (SOCKADDR*)&ClientAddr, &ClientLen);
ConnSocketLst.push_back(NewConnectSocket);
//创建线程,接受数据
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, RecvData, (LPVOID)(&NewConnectSocket), 0, NULL);
}
//关闭套接字
std::list<SOCKET>::iterator it = ConnSocketLst.begin();
for (; it != ConnSocketLst.end();)
{
closesocket(*it);
ConnSocketLst.erase(it++);
}
ConnSocketLst.clear();
closesocket(ListeningSocket);
//清理
WSACleanup();
getchar();
return 0;
}
//接受数据
UINT WINAPI RecvData(LPVOID pParam)
{
//得到套接字
SOCKET Socket = *((SOCKET*)pParam);
//获得数据
char buf[MAXBUF] = {0};
while (1)
{
int nLen = recv(Socket, buf, MAXBUF, 0);// | MSG_PEEK | MSG_OOB);
if (0 < nLen)
{
buf[nLen] = '\0';
std::cout << buf << "\n";
SendData(buf);
//是否退出
if (0 == strcmp(buf, "客户端:\n quit\n"))
{
break;
}
}
else
{
std::cout << "接收数据失败\n";
break;
}
}
closesocket(Socket);
ConnSocketLst.remove(Socket);
/*
std::list<SOCKET>::iterator it = ConnSocketLst.begin();
for (; it != ConnSocketLst.end(); it++)
{
if (*it == Socket)
{
ConnSocketLst.erase(it);
break;
}
}
*/
//_endthreadex(0);
return 0;
}
//发送数据
UINT WINAPI SendData(LPVOID pParam)
{
//得到套接字
char *SendBuf = (char*)pParam;
if (SendBuf == NULL)
{
//将要发送的数据
std::string strSend;
//循环输入并发送数据
while (0 != nFlag)
{
//清空以前的数据并重新输入数据
strSend.clear();
for (;;)
{
char cTemp = getchar();
strSend.append(1, cTemp);
if (cTemp == '\n')
{
strSend.append(1, '\0');
break;
}
}
//设置标志(是否退出)
nFlag = strcmp(strSend.c_str(), "quit\n");
//发送数据前准备
strSend = "服务端:\n " + strSend;
//std::cout << strSend.c_str() << "\n";
int nLeft = (int)strSend.length();
//发送数据
std::list<SOCKET>::iterator it = ConnSocketLst.begin();
for (; it != ConnSocketLst.end(); it++)
{
int nRet = send(*it, strSend.c_str(), nLeft, 0);// | MSG_DONTROUTE | MSG_OOB);
if (nRet == SOCKET_ERROR) {
std::cout << "发送数据失败\n";
}
}
}
//关闭监听套接字
closesocket(ListeningSocket);
}
else
{
int nLeft = (int)strlen(SendBuf);
//发送数据
std::list<SOCKET>::iterator it = ConnSocketLst.begin();
for (; it != ConnSocketLst.end(); it++)
{
int nRet = send(*it, SendBuf, nLeft, 0);// | MSG_DONTROUTE | MSG_OOB);
if (nRet == SOCKET_ERROR) {
std::cout << "发送数据失败\n";
}
}
}
return 0;
}
/************************************************************************/
/*Client.cpp */
/************************************************************************/
#include <WinSock2.h>
#include <iostream>
#include <string>
#include <process.h>
#pragma comment (lib, "WS2_32.lib")
#define MAXBUF 32767
int nFlag = 1; //0表示退出
HANDLE g_Mutex = CreateMutex(NULL, TRUE, NULL); //创建互斥对象
//接受数据
UINT WINAPI RecvData(LPVOID pParam);
//发送数据
UINT SendData(LPVOID pParam);
int main()
{
WSADATA WsaData;
SOCKET ClientSocket;
SOCKADDR_IN ServerAddr;
int Port = 5678;
//初始化版本2.2
if (0 != WSAStartup(MAKEWORD(2, 2), &WsaData))
{
std::cout << "网络初始化失败\n";
goto END;
}
//创建一个新的套接字来建立客户机的连接
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//建立一个SOCKADDR_IN结构,来连接服务器
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port); //主机字节顺序转换为网络字节顺序
ServerAddr.sin_addr.s_addr = inet_addr(("127.0.0.1"));
//用套接字创建一个到服务器的连接
if (0 != connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)))
{
std::cout << "连接服务器失败\n";
goto END;
}
//创建线程,接受数据
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, RecvData, (LPVOID)(&ClientSocket), 0, NULL);
//发送数据
SendData(&ClientSocket);
//等待接收数据的线程结束
while (WAIT_OBJECT_0 != WaitForSingleObject(hThread, INFINITE)) { }
END:
//关闭套接字
closesocket(ClientSocket);
//清理
WSACleanup();
//释放互斥对象
ReleaseMutex(g_Mutex);
getchar();
return 0;
}
//接受数据
UINT WINAPI RecvData(LPVOID pParam)
{
//得到套接字
SOCKET Socket = *((SOCKET*)pParam);
//获得数据
char buf[MAXBUF] = {0};
while (1)
{
int nLen = recv(Socket, buf, MAXBUF, 0);// | MSG_PEEK | MSG_OOB);
if (0 < nLen)
{
buf[nLen] = '\0';
std::cout << buf << "\n";
//是否退出
if (0 == strcmp(buf, "服务端:\n quit\n"))
{
break;
}
}
else
{
std::cout << "与服务器断开连接\n";
break;
}
}
nFlag = 0;
return 0;
}
//发送数据
UINT SendData(LPVOID pParam)
{
//得到套接字
SOCKET Socket = *((SOCKET*)pParam);
//将要发送的数据
std::string strSend;
//循环输入并发送数据
while (0 != nFlag)
{
//清空以前的数据并重新输入数据
strSend.clear();
for (;;)
{
char cTemp = getchar();
strSend.append(1, cTemp);
if (cTemp == '\n')
{
strSend.append(1, '\0');
break;
}
}
//发送数据前准备
strSend = "客户端:\n " + strSend;
int nLeft = (int)strSend.length();
int nRet = send(Socket, strSend.c_str(), nLeft, 0);// | MSG_DONTROUTE | MSG_OOB);
if (nRet == SOCKET_ERROR) {
std::cout << "发送数据失败\n";
}
}
return 0;
}