Linux C/C++实现socket传输任意字符串(基于TCP实现)

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

最后实现的效果如下所示:

猜你喜欢

转载自blog.csdn.net/liu548zhou/article/details/81434754