简介
课程的团队项目,初学socket和单例模式,对socket的调用方式进行了封装(Windows系统下),
对于socket的具体函数的了解较少,故没有充足的注释
代码
服务端代码如下
Servre.h
#pragma once
#include <iostream>
#include <cstdlib>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
namespace server
{
class Serverh
{
private:
WORD sockVersion;
WSADATA wsaData;
sockaddr_in sin;
SOCKET slisten;
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen;
char revData[255];
u_short ip;
static Server* instance;
Server();
//Server(Server&) = delete;
//Server& operator= (const Server&) = delete;
public:
/** 判断是否初始化成功 */
bool isInit();
/** 循环接收客户端信息 */
void start();
/** 修改ip */
void setIp(u_short);
/** 获取单例模式 */
static Server* getInstance();
};
}
Server.cpp
#include "Server.h"
using namespace server;
Server* Server::instance = NULL;
Server::Server()
{
ip = 8888;
sockVersion = MAKEWORD(2, 2);
//slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sin.sin_family = AF_INET;
sin.sin_port = htons(ip);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
nAddrlen = sizeof(remoteAddr);
}
void server::Server::setIp(u_short IP)
{
this->ip = IP;
}
Server* server::Server::getInstance()
{
if (Server::instance == NULL)
instance = new Server;
return instance;
}
bool server::Server::isInit()
{
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return false;
}
slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
printf("socket error !");
return false;
}
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("bind error !");
return false;
}
if (listen(slisten, 5) == SOCKET_ERROR)
{
printf("listen error !");
return false;
}
return true;
}
void server::Server::start()
{
if (!isInit())
return;
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));
//接收数据
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);
printf("\n");
}
//发送数据
const char* sendData = "你好,TCP客户端!\n";
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return;
}
客户端代码如下:
Cilent.h
#pragma once
#include<WINSOCK2.H>
#include<stdio.h>
#include<iostream>
#include<cstring>
#pragma comment(lib, "ws2_32.lib")
namespace cilent
{
class Cilent
{
public:
/** 获取单例模式实例 */
static Cilent* getInstance();
/** 运行入口 */
void start();
private:
WORD sockVersion;
WSADATA wasdata;
sockaddr_in serAddr;
SOCKET sclient;
std::string data;
const char* sendData;
char revData[255];
u_short ip;
static Cilent* instance;
Cilent();
};
}
Cilent.cpp
#include "Cilent.h"
using namespace cilent;
Cilent* Cilent::instance = NULL;
Cilent::Cilent()
{
sockVersion = MAKEWORD(2, 2);
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("106.52.165.96");
}
Cilent* Cilent::getInstance()
{
if (instance == NULL)
instance = new Cilent;
return instance;
}
void Cilent::start()
{
if (WSAStartup(sockVersion, &wasdata) != 0)
{
std::cout << "初始化失败" << std::endl;
return;
}
while (true) {
sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == INVALID_SOCKET)
{
printf("invalid socket!");
return;
}
if (connect(sclient, (sockaddr*)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{ //连接失败
printf("connect error !");
closesocket(sclient);
return;
}
std::cin >> data;
sendData = data.c_str(); //string转const char*
//char * sendData = "你好,TCP服务端,我是客户端\n";
send(sclient, sendData, strlen(sendData), 0);
//send()用来将数据由指定的socket传给对方主机
//int send(int s, const void * msg, int len, unsigned int flags)
//s为已建立好连接的socket,msg指向数据内容,len则为数据长度,参数flags一般设0
//成功则返回实际传送出去的字符数,失败返回-1,错误原因存于error
char recData[255];
int ret = recv(sclient, recData, 255, 0);
if (ret > 0) {
recData[ret] = 0x00;
printf(recData);
}
closesocket(sclient);
}
}
总结
在修改成单例模式时遇到了个bug,如果
sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
不在Start里调用,则会出现socket error.