一、单个sokect监听
#ifdef WIN32
//#include <windows.h>
#include<ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#unclude <stdlib.h>
#include <sys/socket.h>
#incklude <
#define closesocket close
#endif
#include <stdio.h>
#include<string>
int main(int argc, char* argv[])
{
#ifdef WIN32
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
#endif
for (int i = 0; i < 1; i++)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
printf("create socket failed!\n");
return -1;
}
unsigned int port = 8080;
if (argc > 1) {
port = atoi(argv[1]);
}
sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议
saddr.sin_port = htons(port); //端口号
saddr.sin_addr.s_addr = htonl(0); //ip地址
if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0) {
printf("bind port %d failed!\n", port);
return -2;
}
printf("bind port %d success!\n", port);
listen(sock, 10); //第二个参数表示缓冲区大小,即等待连接队列的最大长度 成功返回0,失败返回-1
sockaddr_in caddr;
socklen_t len = 0;
int client = accept(sock, (sockaddr*)&caddr, &len); //成功会返回一个新的sockt,失败返回-1
printf("accept client %d\n", client);
char* ip = inet_ntoa(caddr.sin_addr); //获取ip号
unsigned short cport = ntohs(caddr.sin_port); //获取端口号
printf("client ip id %s,port is %d\n", cport, ip);
/*函数原型:int accept( int fd, struct socketaddr* addr, socklen_t* len);
* 功能:获取请求连接,返回新的套接字描述符
参数说明:
fd:套接字描述符。
addr:返回连接着的地址
len:接收返回地址的缓冲区长度 */
char buf[1024] = { 0 };
for (;;) {
int recvlen = recv(client, buf, sizeof(buf) - 1, 0);
/*
* 函数原型:int recv(socket s, char FAR* buf, int len, int flags);
函数说明:recv()用来接收指定的socket传来的数据,并把数据传到由参数buf指向的内存空间。
参数说明:
socket:一个标识已连接套接口的描述字。
buf:用于接收数据的缓冲区。
len:缓冲区长度。
flags:指定调用方式。取值:MSG_PEEK 查看当前数据,数据将被复制到缓冲区中,但并不从输入队列中删除;MSG_OOB 处理带外数据。
返回值:若无错误发生,recv()返回读入的字节数。如果连接已中止,返回0。否则的话,返回SOCKET_ERROR错误,
应用程序可通过WSAGetLastError()获取相应错误代码。
*/
if (recvlen <= 0) break;
buf[recvlen] = '\0'; //在字符串结尾加\0
if (strstr(buf, "quit") != NULL) { //接收到quit退出
char re[] = "quit success!\n";
send(client, re, strlen(re) + 1, 0);
break;
/*
函数原型:
int send( socket s, const char FAR* buf, int len, int flags);
函数说明:向一个已连接的套接口发送数据。
参数说明:
s:一个用于标识已连接套接口的描述字。
buf:包含待发送数据的缓冲区。
len:缓冲区中数据的长度。
flags:调用执行方式。
返回值:如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。
*/
}
int sendlen = send(client, "OK", 3, 0); //接收到数据返回ok
printf("recv %s\n", buf);
}
closesocket(client);
printf("[%d]", sock);
//closesocket(sock);
}
getchar();
return 0;
}
二、封装成类
1.Xtcp.h
#include<string>
class Xtcp
{
public:
Xtcp();
virtual ~Xtcp();
int CreatSocket();
bool Bind(unsigned short port);
Xtcp Accept();
void Close();
int Recv(char* buf, int bufsize);
int Send(const char* buf, int sendsize);
public:
int sock = -1;
unsigned short port = 0;
std::string ip;
};
2.Xtcp.cpp
#include "Xtcp.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#define socklen_t int
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#define closesocket close
#endif
#include<thread>
using namespace std;
Xtcp::Xtcp()
{
#ifdef WIN32
static bool first = true;
if (first)
{
first = false;
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
}
#endif
}
int Xtcp::CreatSocket() {
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
printf("create socket failed!\n");
return -1;
}
printf("sock num: %d creat success!\n", sock);
return sock;
}
bool Xtcp::Bind(unsigned short port)
{
if (sock < 0)
CreatSocket();
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = htonl(0);
if (::bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)
{
printf("bind port %d failed!\n", port);
return false;
}
printf("bind port %d success!\n", port);
listen(sock, 10);
return true;
}
Xtcp Xtcp::Accept() {
Xtcp tcp;
sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int client = accept(sock, (sockaddr*)&caddr, &len); //成功会返回一个新的sockt,失败返回-1
if (client <= 0) return tcp;
printf("accept client %d\n", client);
tcp.ip = inet_ntoa(caddr.sin_addr); //获取ip号
tcp.port = ntohs(caddr.sin_port); //获取端口号
printf("client ip id %s,port is %d\n", tcp.ip.c_str(), tcp.port);
}
void Xtcp::Close() {
if (sock < 0) return;
closesocket(sock);
}
int Xtcp::Recv(char* buf, int bufsize) {
return recv(sock, buf, bufsize, 0);
}
int Xtcp::Send(const char* buf, int sendsize) {
int sendedsize = 0; //已发送长度
while (sendedsize != sendedsize) { //没有发送完毕就会一直发
int len = send(sock, buf + sendedsize, sendsize - sendedsize, 0);
if (len <= 0) break;
sendedsize += len;
}
return sendedsize;
}
Xtcp::~Xtcp() {
}
3.main.cpp
#include<stdlib.h>
#include"Xtcp.h"
#include<thread> //c++11中的线程库
#include <string.h>
class TcpThread {
public:
void MainFunc() {
char buf[1024] = { 0 };
for (;;) {
int recvlen = client.Recv(buf, sizeof(buf) - 1);
if (recvlen <= 0) break;
buf[recvlen] = '\0'; //在字符串结尾加\0
if (strstr(buf, "quit") != NULL) { //接收到quit退出
char re[] = "quit success!\n";
client.Send(re, strlen(re) + 1);
break;
}
int sendlen = client.Send("OK", 4); //接收到数据返回ok
printf("recv %s\n", buf);
}
client.Close();
delete this;
}
Xtcp client;
};