簡介
- 客戶端連接后放到線程中運行
- Socket相關代碼封裝
C++線程
這里使用c++11標準的線程庫。
#include <thread>
編譯時候出現
thread_1.png
根據錯誤提示編譯命令后加入
-std=c++0x
即可,對于使用的線程需要引入庫-lpthread
線程使用
線程的調用我們定義一個SocketThread類來進行
SocketThread* st=new SocketThread(connfd);
thread t(&SocketThread::run,st);
t.detach();
然后我們將數據讀取的方法放到SocketThread中
void run(){
int n=0;
cout<<"new thread for socket "<<this->sock<<endl;
char buff[1024];
for(;; ) {
n = recv(this->sock,buff,1024,0);
if(n<=0) {
//如果客戶端斷開了,這里就跳出循環
break;
}
buff[n] = '\0';
printf("%d=>%s",n,buff);
}
close(this->sock);
cout<<this->sock<<" closed"<<endl;
}
注意
當我么使用c++的語法,并使用std命名空間后發現客戶端連不上服務端。這里是bind方法出現了問題。使用了命名空間中的bind。這里需要是用全局的bind方法::bind
即可。
Socket相關類封裝
這里我們將客戶端和服務的的操作封裝到一個類XTcp中,服務的接受連接后,生成一個新的Tcp對象,并將指針返回,然后線程類XThread持有XTcp的指針。
XTcp.h
#include <iostream>
using namespace std;
class XTcp{
private:
int sock;
public:
XTcp();
void setSock(int sock);
int getSock();
int createSocket();
int bindPort(unsigned short port);
int listenSocket();
int receive(char *buf,int len);
int sendData(char *buf,int len);
int connectServer(int port);
XTcp* acceptClient();
int closeSocket();
~XTcp();
};
XTcp.cpp
#include "XTcp.h"
#include "stdio.h"
//socket相關函數需要
#include <sys/types.h>
#include <sys/socket.h>
//close函數需要
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <arpa/inet.h>
//c++ 11標準線程
#include <thread>
#include "XThread.h"
XTcp::XTcp(){
sock=-1;
}
void XTcp::setSock(int sock){
this->sock=sock;
}
int XTcp::getSock(){
return this->sock;
}
int XTcp::createSocket(){
//創建一個socket
this->sock=socket(AF_INET,SOCK_STREAM,0);
if(this->sock==-1) {
cout<<"create socket failed"<<endl;
}
return this->sock;
}
int XTcp::bindPort(unsigned short port){
struct sockaddr_in sockaddr;
memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family=AF_INET;
sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
sockaddr.sin_port=htons(port);
::bind(sock,(struct sockaddr *)&sockaddr,sizeof(sockaddr));
return 0;
}
/**
* 開始監聽
*/
int XTcp::listenSocket(){
listen(sock,10);
return 0;
}
/**
* 接受客戶端的連接,如果連接成功就返回連接后的XTcp
*/
XTcp* XTcp::acceptClient(){
int connfd;
struct sockaddr_in sockaddrClient;
int clientl=sizeof(sockaddrClient);
printf("wait for client connect\n" );
// if((connfd = accept(sock,NULL,NULL))==-1) {
if((connfd = accept(sock,(struct sockaddr*)&sockaddrClient,(socklen_t *)&clientl))==-1) {
printf("accpet socket error: %s errno :%d\n",strerror(errno),errno);
}
char cilentIp[20];
unsigned short port= ntohs(sockaddrClient.sin_port);
const char *ip=inet_ntop(AF_INET,(void *)&sockaddrClient.sin_addr,cilentIp,16);
printf("client=> %s:%d\n",cilentIp,port);
XTcp* xTcpClient=new XTcp;
xTcpClient->setSock(connfd);
//開啟線程接受數據
XThread* st=new XThread(xTcpClient);
thread t(&XThread::run,st);
t.detach();
return xTcpClient;
}
int XTcp::connectServer(int port){
const char * serverIp="127.0.0.1";
sockaddr_in sockaddr;
memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
//轉換ip地址
inet_pton(AF_INET,serverIp,&sockaddr.sin_addr);
if((connect(sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) < 0 )
{
printf("connect error :[%s] errno: %d\n",strerror(errno),errno);
exit(0);
}
cout<<"send msg to server:"<<endl;
char buf[1024];
while (true) {
/* code */
fgets(buf,1024,stdin);
if(strcmp(buf,"exit\n")==0) {
//輸入exit后退出
break;
}
int size=sendData(buf,sizeof(buf));
//寫數據是發生異常
if(size<=0) {
break;
}
}
//關閉客戶端socket
closeSocket();
}
/*
* 接受數據
*/
int XTcp::receive(char *buf,int len){
int n = recv(this->sock,buf,len,0);
return n;
}
/**
* 發送數據
*/
int XTcp::sendData(char *buf,int len){
if(sock<0) {
cout<<"socket is invalid"<<endl;
return -1;
}
if(len<=0) {
return 0;
}
int totalSize=0;
while (totalSize<len) {
/* code */
int size=send(sock,buf+totalSize,strlen(buf)-totalSize,0);
if(size<=0)
break;
totalSize+=size;
}
return totalSize;
}
/**
* 關閉socket
*/
int XTcp::closeSocket(){
int ret=0;
if(sock==-1) {
cout<<"socket is not start"<<endl;
}else if(sock==-1) {
cout<<"socket have already closed"<<endl;
}else{
ret =close(sock);
if(ret==-1) {
printf("socket close failed\n");
}else{
printf("%d close success!\n",sock );
}
}
sock=-2;
return ret;
}
XTcp::~XTcp(){
cout<<"~XTcp"<<endl;
}
XThread.h
#include <iostream>
using namespace std;
class XThread {
private:
XTcp* sock;
public:
XThread(XTcp* sock){
this->sock=sock;
}
~XThread(){
cout<<"release"<<endl;
}
void run(){
int n=0;
cout<<"new thread for socket "<<this->sock->getSock()<<endl;
char buff[1024];
for(;; ) {
n = sock->receive(buff,1024);
if(n<=0) {
//如果客戶端斷開了,這里就跳出循環
break;
}
buff[n] = '\0';
printf("%d=>%s",n,buff);
}
sock->closeSocket();
}
};
Makefile
all: xserver xclient
xserver : xserver.cpp XTcp.h XTcp.cpp XThread.h
g++ -lpthread -o xserver xserver.cpp XTcp.cpp -std=c++0x
xclient : xclient.cpp XTcp.h XTcp.cpp
g++ -o $@ $+ -std=c++0x
.PHONY : clean
clean :
-rm xserver xclient