C++实现 socket 传输任意字符串,在网上看到了许多很不错的代码,但大都是一端发送字符串,另外一端循环接收字符串,并没有对字符串的长度进行比较,试想:若在传完字符串后,还有其他的数据传送,那么在这样的情况下,接收端循环接收字符串就存在很大的弊端,因此在这里实现的是先将字符串的长度传送到接收端,而后紧接着传输字符串本身,这样在接收端就能先接收到字符串的长度,然后根据接收的长度接收字符串本身的数据。
客户端实现如下:
client.cpp
#include <iostream>
#include <signal.h>
#include <string>
#include <stdio.h>
#include "TCPClient.h"
TCPClient tcp;
using namespace std;
void sig_exit(int s)
{
tcp.exit();
exit(0);
}
int main(int argc, char *argv[])
{
string message;
getline(cin,message);
signal(SIGINT, sig_exit);
tcp.setup("127.0.0.1",11999);
tcp.Send(message);
string rec = tcp.receive();
if( rec != "" )
{
cout << "Server Response:" << rec << endl;
}
return 0;
}
TCPClient.cpp
#include "TCPClient.h"
TCPClient::TCPClient(){
sock = -1;
port = 0;
address = "";
}
bool TCPClient::setup(string address , int port){
if(sock == -1)
{
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
cout << "Could not create socket" << endl;
}
}
if(inet_addr(address.c_str()) == (unsigned)-1)
{
struct hostent *he;
struct in_addr **addr_list;
if ( (he = gethostbyname( address.c_str() ) ) == NULL)
{
herror("gethostbyname");
cout<<"Failed to resolve hostname\n";
return false;
}
addr_list = (struct in_addr **) he->h_addr_list;
for(int i = 0; addr_list[i] != NULL; i++)
{
server.sin_addr = *addr_list[i];
break;
}
}
else
{
server.sin_addr.s_addr = inet_addr( address.c_str() );
}
server.sin_family = AF_INET;
server.sin_port = htons( port );
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return false;
}
return true;
}
bool TCPClient::Send(string data){
cout<< "the data is:"<< data <<endl;
if(sock != -1) {
int length = data.length();
if(send(sock, &length, sizeof(int), 0 ) < 0 ){
cout << "Send length failed : " << endl;
return false;
}
if( send(sock , data.c_str() , data.length() , 0) < 0){
cout << "Send failed : " << data << endl;
return false;
}
}
else
return false;
return true;
}
string TCPClient::receive(int size){
int length = 0;
recv(sock,&length,sizeof(int),0);
char* message = (char*)malloc(length+1);
memset(message, 0, length+1);
recv(sock,message,length,0);
string reply = message;
free(message);
return reply;
}
void TCPClient::exit()
{
close( sock );
}
TCPClient.h
#ifndef TCP_CLIENT_H
#define TCP_CLIENT_H
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netdb.h>
#include <vector>
#include "../Agent/Base.h"
using namespace std;
class TCPClient
{
private:
int sock;
std::string address;
int port;
struct sockaddr_in server;
public:
TCPClient();
bool setup(string address, int port);
bool Send(string data);
string receive(int size = 4096);
string read();
void exit();
};
#endif
在Linux 下进行编译,其编译命令如下:
g++ -Wall -o client client.cpp TCPClient.cpp -std=c++11 -lpthread
服务端代码如下:
server.cpp
#include <iostream>
#include "TCPServer.h"
TCPServer tcp;
int main()
{
//设置服务器端口
tcp.setup(11999);
tcp.receive();
return 0;
}
TCPClient.cpp
#include "TCPServer.h"
void* TCPServer::Task(void *arg)
{
int sock = (long)arg;
pthread_detach(pthread_self());
//接收客户端字符串
if(sock != -1){
int length = 0;
if(sizeof(int)!=recv(sock,&length,sizeof(int),0)){
printf("recv length error...");
}
char* message = (char*)malloc(length+1);//length + 1 是保证传输的字符串中结束符的存在
memset(message, 0 , length);//清空缓冲区的内容
if(length != recv(sock,message,length,0)){
printf("recv string error...");
}
//以下将收到的字符串加上 --from server!!! 后发送回客户端
string returnstr = message;
returnstr += " --from server!!!";
int returnstr_length = returnstr.length();
send(sock, &returnstr_length, sizeof(int),0);//先将字符串的长度发送给客户端
send(sock,returnstr.c_str(),returnstr.length(),0);
}
return 0;
}
void TCPServer::setup(int port)
{
sockfd=socket(AF_INET,SOCK_STREAM,0);
memset(&serverAddress,0,sizeof(serverAddress));
serverAddress.sin_family=AF_INET;
serverAddress.sin_addr.s_addr=htonl(INADDR_ANY);
serverAddress.sin_port=htons(port);
bind(sockfd,(struct sockaddr *)&serverAddress, sizeof(serverAddress));
listen(sockfd,5);
}
void TCPServer::receive()
{
while(1)
{
socklen_t sosize = sizeof(clientAddress);
newsockfd = accept(sockfd,(struct sockaddr*)&clientAddress,&sosize);
inet_ntoa(clientAddress.sin_addr);
pthread_create(&serverThread,NULL,&Task,(void *)newsockfd);
}
close(sockfd);
close(newsockfd);
}
TCPClient.h
#ifndef TCP_SERVER_H
#define TCP_SERVER_H
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
using namespace std;
#define MAXPACKETSIZE 4096
class TCPServer
{
public:
int sockfd, newsockfd, n, pid;
struct sockaddr_in serverAddress;
struct sockaddr_in clientAddress;
pthread_t serverThread;
void setup(int port);
void receive();
private:
static void * Task(void * argv);
};
#endif
Server 端编译的命令如下:
g++ -Wall -o server server.cpp TCPServer.cpp -std=c++11 -lpthread
最后实现的效果如下所示: