实现了C++下的TCP socket通信。由于不知道发送/接收信息的长度,因此,实现中先发送消息的长度,然后再发送消息内容;接收也一样,先接收消息长度,然后再接收消息的具体内容。实现代码在Linux下测试通过。
原来写的程序是有问题的,当发送的报文太长时,接收到的报文与发送的报文并不是一致的(接收到的报文不全)。找了一些资料发现“如果是阻塞的:man中的说明:
It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
如果是非阻塞,因为可能读的时候所有的数据还没有接收完,read只返回当前socket缓冲中有的数据。”(http://bbs.byr.cn/#!article/Linux/106207)
修改后的server端程序如下。
server端的代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <iostream> using namespace std; void error(const string msg) { perror(msg.c_str()); exit(1); } void send_msg(int &sockfd, const string message) { int n = 0; int length = message.length(); n = write(sockfd, (char *) &length, sizeof(length)); if(n < 0) { error("Error: cannot send message length to server!\n"); } n = write(sockfd, message.c_str(), length); if(n < 0) { error("Error: cannot send message to server!\n"); } } void recv_msg(int &sockfd) { int n = 0; // fisrt accept the length of message int length = 0; n = read(sockfd, (char *) &length, sizeof(length)); cout << "MSG Length: " << length << endl; if(n < 0) { error("Error: cannot read message length from client!\n"); } // receive message from client int buffer_length = length + 1; char * buffer = new char[buffer_length]; bzero(buffer, buffer_length); int byte_read = 0; while(byte_read < length) { n = read(sockfd, buffer + byte_read, length - byte_read); if(n < 0) { error("Error: cannot read message from client!\n"); } byte_read += n; } cout << "MSG: " << buffer << endl; } int main(int argc, char* argv[]) { int sockfd, newsockfd, portno; socklen_t clilen; struct sockaddr_in serv_addr, cli_addr; if(argc < 2) { error("Error: no port provided!\n"); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { error("Error: cannot open socket!\n"); } bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { error("Error: binding error!\n"); } listen(sockfd, 5); // backlog = 5, defines the maximum length to which the queue of pending connections for sockfd may grow clilen = sizeof(cli_addr); while(1) { newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if(newsockfd < 0) { error("Error: cannot accept!\n"); } // recieve message cout << "receiving message...\n"; recv_msg(newsockfd); cout << "******************************\n"; // send message to client cout << "sending message...\n"; send_msg(newsockfd, "Successfully received!"); close(newsockfd); } close(sockfd); return 0; }
client端的代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <iostream> using namespace std; void error(const string msg) { perror(msg.c_str()); exit(1); } void send_msg(int &sockfd, const string message) { int n = 0; int length = message.length(); n = write(sockfd, (char *) &length, sizeof(length)); if(n < 0) { error("Error: cannot send message length to server!\n"); } n = write(sockfd, message.c_str(), length); if(n < 0) { error("Error: cannot send message to server!\n"); } } void recv_msg(int &sockfd) { int n = 0; // fisrt accept the length of message int length = 0; n = read(sockfd, (char *) &length, sizeof(length)); cout << "MSG Length: " << length << endl; if(n < 0) { error("Error: cannot read message length from client!\n"); } // receive message from client int buffer_length = length + 1; char * buffer = new char[buffer_length]; bzero(buffer, buffer_length); int byte_read = 0; while(byte_read < length) { n = read(sockfd, buffer + byte_read, length - byte_read); if(n < 0) { error("Error: cannot read message from client!\n"); } byte_read += n; } cout << "MSG: " << buffer << endl; } int main(int argc, char * argv[]) { int sockfd, portno; struct sockaddr_in serv_addr; struct hostent *server; // char buffer[256]; if(argc < 3) { error("Error! Usage: cmd hostname port\n"); } portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { error("Error: cannot open socket!\n"); } server = gethostbyname(argv[1]); if(server == NULL) { error("Error: cannot find the server!"); } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if(connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { error("Error: cannot connect to server!\n"); } cout << "Please enter the message: \n"; string message = ""; getline(cin, message); // send message cout << "sending message...\n"; send_msg(sockfd, message); // receive message from server cout << "receiving message...\n"; recv_msg(sockfd); cout << "******************************\n"; close(sockfd); return 0; }
执行结果如下图所示:
参考文献:
http://www.linuxhowtos.org/C_C++/socket.htm
http://stackoverflow.com/questions/666601/what-is-the-correct-way-of-reading-from-a-tcp-socket-in-c-c
http://bbs.byr.cn/#!article/Linux/106207