TCP echo_server(C++)回射服务器实现以及问题记录
基本运行方式:
- 客户端接收用户输入的字符串并发送到服务器端
- 服务器端将接收的字符串数据传回客户端
- 服务器端和客户端之间的字符串回射一直执行到客户端输入Q为止
服务器端实现:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <memory.h>
#include <netinet/in.h>
const int buf_size = 1024;
void error_handler(std::string message);
int main(int argc, char* argv[])
{
int serv_sock, clt_sock;
char message[buf_size];
int str_len, i;
struct sockaddr_in serv_adr,clt_adr;
socklen_t clt_adr_len;
if(argc != 2)
{
printf("usage %s <IP> <port>", argv[0]);
exit(1);
}
// const char* ip = argv[1];
// int port = atoi(argv[2]);
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if(serv_sock == -1)
error_handler("socket() error");
memset(&serv_adr, 0, sizeof serv_adr);
memset(&clt_adr, 0, sizeof(clt_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htons(INADDR_ANY);
//serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handler("bind() error");
if(listen(serv_sock, 5) == -1)
error_handler("listen() error");
clt_adr_len = sizeof(clt_sock);
// for(int i=0;i<5;++i)
// {
// clt_sock = accept(serv_sock, (struct sockaddr*)&clt_adr, &clt_adr_len);
// if(clt_sock == -1)
// error_handler("accept() error");
// else
// printf("Connnected client %d. \n", i+1);
// while((str_len = read(clt_sock, message, buf_size)) != 0)
// write(clt_sock, message, str_len);
// close(clt_sock);
// }
printf("accept........\n");
clt_sock = accept(serv_sock, (struct sockaddr*)&clt_adr, &clt_adr_len);
if(clt_sock == -1)
error_handler("accept() error");
else
printf("accept success\n");
while((str_len = read(clt_sock, message, buf_size)) != 0)
write(clt_sock, message, str_len);
close(clt_sock);
close(serv_sock);
return 0;
}
void error_handler(std::string message)
{
fputs(message.c_str(), stderr);
fputc('\n', stderr);
exit(1);
}
客户端实现:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <memory.h>
const int buf_size = 1024;
void error_handler(std::string message);
int main(int argc, char* argv[])
{
int sock;
char message[buf_size];
int str_len;
int recv_len, recv_cnt;
struct sockaddr_in serv_adr;
socklen_t clt_adr_len;
if(argc != 3)
{
printf("usage %s <IP> <port>", argv[0]);
exit(1);
}
sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock == -1)
error_handler("socket() error");
memset(&serv_adr, 0, sizeof serv_adr);
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handler("connect() error");
else
puts("Connected............");
while(1)
{
fputs("Input message (Q to quit) : ", stdout);
fgets(message, buf_size, stdin);
if(!strcmp(message, "q\n")||!strcmp(message, "Q\n"))
break;
str_len = write(sock, message, strlen(message));
//str_len = read(sock, message, buf_size - 1);
recv_len = 0;
while(recv_len < str_len)
{
recv_cnt = read(sock, &message[recv_len], buf_size - 1);
if(recv_cnt == -1)
error_handler("read() error");
recv_len += recv_cnt;
}
message[str_len] = 0;
printf("Message from server : %s", message);
}
close(sock);
return 0;
}
void error_handler(std::string message)
{
fputs(message.c_str(), stderr);
fputc('\n', stderr);
exit(1);
}
运行结果:
在tty1上运行服务器端程序
在tty2上运行客户端程序
遇到的问题:
服务器端正常监听,客户端连接失败,connect( ) 返回 -1
解决:
使用tcpdump抓包,显示连接请求被拒绝,查看代码并没有发现明显错误,怀疑是端口没有被使用。
所以查看当前进程占用的是哪个端口:
$ netstat -anp
发现服务器端口正常监听,但是端口不是8000,而是52053,这意味着操作系统随机分配了一个端口,而并未使用指定的端口8000
查看服务器端代码,发现htonl( )函数使用错误,应该使用htons( )函数(程序内已经和改正)
因为ubuntu使用的是小端字节序,而使用htonl函数时,进行32位转换,所以htonl(8000)结果为0。
使用htons()就可以解决