我正在用C实现套接字程序。
节目说明:
连接服务器和客户端后,客户端向服务器发送命令
服务器从客户端接收请求并执行它
服务器将执行结果发送给客户端
客户端将显示该服务器的执行和显示。
我的问题:
服务器:我将execvp()
功能的结果放入管道pipefd[1]
,然后将此数据发送给send()
的客户端。
的客户端:
我收到recv()
数据到服务器并显示。
但它不起作用。
我想要的结果:
客户 :ls
服务器:
a.txt b.pdf c.jpg
客户端:
a.txt b.pdf c.jpg
这是我的代码:
服务器
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#define MAXPENDING 5
#define BUFFSIZE 32
#define MAX 128
void Die(char *mess)
{
perror(mess);
exit(1);
}
void setup(char inputBuffer[], char *args[], int *background) //Ham xu li (cat) chuoi lenh
{
const char s[4] = " \t\n";
char *token;
token = strtok(inputBuffer, s);
int i = 0;
while( token != NULL)
{
args[i] = token;
i++;
//printf("%s\n", token);
token = strtok(NULL,s);
}
args[i] = NULL;
}
void HandeClient(int sock){
char buffer[BUFFSIZE];
int received = -1;
char data[MAX];
data[0] = '\0';
/*recv() from client;*/
if((received = recv(sock, buffer,BUFFSIZE,0))<0){
Die("Failed");
}
buffer[received] = '\0';
strcat (data, buffer);
while(received>0)
{
/* send() from server; //acknowledge to client */
if(send(sock,buffer, received,0)!= received){
Die("Failed");
}
/* recv() from client; */
if((received=recv(sock,buffer,BUFFSIZE,0))<0){
Die("Failed");
}
buffer[received] = '\0';
strcat (data, buffer);
}
puts (data);
{
char *args[100];
setup(data,args,0);
// pipe
int pipefd[2],lenght;
pipe(pipefd);
pid_t pid = fork();
char path[MAX];
if(pid>0)
{
// parent process // write to pipe
execvp(args[0],args);
dup2(1,pipefd[1]);
close(pipefd[0]);
write(STDOUT_FILENO,pipefd[1],strlen(pipefd[1]));
close(pipefd[1]);
while (wait(NULL) != pid);
}
else
if(pid==0)
{
//child process // read from pipe
close(pipefd[1]);
while(lenght=read(pipefd[0],path,1) > 0){
// send the result of execvp for client.
if(send(sock,path,strlen(path),0) != strlen(path) ){
Die("Failed");
}
}
close(pipefd[0]);
exit(1);//
}
else
{
printf("Error !\n");
exit(0);//
}
}
if (strcmp (data, "exits")==0)
{
exit (1);
}
close(sock);
}
int main(int argc, char const *argv[])
{
int serversock,clientsock;
struct sockaddr_in echoserver, echoclient;
/*if(argc !=2)
{
fprintf(stderr, "USAGE: echoserver <port>\n");
exit(0);
}*/
if((serversock = socket(PF_INET, SOCK_STREAM,IPPROTO_TCP))<0){
Die("Failed");
}
memset(&echoserver,0,sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr= htonl(INADDR_ANY);
echoserver.sin_port = htons(atoi(argv[1]));
if(bind(serversock, (struct sockaddr *) & echoserver,sizeof(echoserver))<0){
Die("Failed");
}
if(listen(serversock,MAXPENDING)<0){
Die("Failed");
}
while(1)
{
unsigned int clientlen = sizeof(echoclient);
if((clientsock =
accept(serversock,(struct sockaddr *) &echoclient,
&clientlen))<0){
Die("Failed");
}
fprintf(stdout, "Client connected: %s\n",
inet_ntoa(echoclient.sin_addr));
fprintf(stdout,"Message from client:");
HandeClient(clientsock);
}
return 0;
}
客户端:
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define BUFFSIZE 32
/// Client chuyen mot chuoi ki tu, sau khi an enter n gui cho server roi ket thuc
void Die(char *mess)
{
perror(mess);
exit(1);
}
int main(int argc, char *argv[])
{
while(1){
int sock;
struct sockaddr_in echoserver;
char buffer[BUFFSIZE];
unsigned int echolen;
int received = 0;
if (argc != 3)
{
fprintf(stderr, "USAGE: TCPecho <server_ip> <word> <port>\n");
exit(1);
}
/* Create the TCP socket */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
Die("Failed to create socket");
}
/* Construct the server sockaddr_in structure */
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = inet_addr(argv[1]);
echoserver.sin_port = htons(atoi(argv[2]));
/* Establish connection */
if (connect(sock,(struct sockaddr *) &echoserver,sizeof(echoserver)) < 0)
{
Die("Failed to connect with server");
}
/* Send the word to the server */
//tao mot chuoi s, chuoi s nhan ki tu tu ban phim, roi chuyen cho phia server
char s[100];
fgets(s,100,stdin);
echolen = strlen(s);
/* send() from client; */
if (send(sock, s, echolen, 0) != echolen)
{
Die("Mismatch in number of sent bytes");
}
/* Receive the word back from the server */
fprintf(stdout, "Message from server: ");
while (received < echolen)
{
int bytes = 0;
/* recv() from server; */
if ((bytes = recv(sock, buffer, BUFFSIZE-1, 0)) < 1)
{
Die("Failed to receive bytes from server");
}
received += bytes;
buffer[bytes] = '\0';
/* Assure null terminated string */
fprintf(stdout, buffer);
}
fprintf(stdout, "\n");
close(sock);
if(strcmp(s,"exit") == 0)
exit(0);
}
}
答案 0 :(得分:1)
我将代码修改为我认为是您的预期行为。请注意,execvp()
正在执行,而不是原始代码中的开头。我修复了服务器和客户端试图接收其中一个应该发送的几个地方。
我添加了while循环以允许执行命令,直到客户端类型退出。
请参阅代码中的注释。
服务器强>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#define MAXPENDING 5
#define BUFFSIZE 2048
#define MAX 2048
void Die(char *mess)
{
perror(mess);
exit(1);
}
void setup(char inputBuffer[], char *args[], int *background) //Ham xu li (cat) chuoi lenh
{
const char s[4] = " \t\n";
char *token;
token = strtok(inputBuffer, s);
int i = 0;
while( token != NULL)
{
args[i] = token;
i++;
//printf("%s\n", token);
token = strtok(NULL,s);
}
args[i] = NULL;
}
void HandeClient(int sock){
char buffer[BUFFSIZE];
int received = -1;
char data[MAX];
memset(data,0,MAX);
while(1) { // this will make server wait for another command to run until it receives exit
data[0] = '\0';
if((received = recv(sock, buffer,BUFFSIZE,0))<0){
Die("Failed");
}
buffer[received] = '\0';
strcat (data, buffer);
if (strcmp(data, "exit")==0) // this will force the code to exit
exit(0);
/* This block causes server to wait for more data from client when all data are already received.
while(received>0)
{
if(send(sock,buffer, received,0)!= received){
Die("Failed");
}
if((received=recv(sock,buffer,BUFFSIZE,0))<0){
Die("Failed");
}
buffer[received] = '\0';
strcat (data, buffer);
}
*/
puts (data);
char *args[100];
setup(data,args,0);
int pipefd[2],lenght;
if(pipe(pipefd))
Die("Failed to create pipe");
pid_t pid = fork();
char path[MAX];
if(pid==0)
{
close(1); // close the original stdout
dup2(pipefd[1],1); // duplicate pipfd[1] to stdout
close(pipefd[0]); // close the readonly side of the pipe
close(pipefd[1]); // close the original write side of the pipe
execvp(args[0],args); // finally execute the command
}
else
if(pid>0)
{
close(pipefd[1]);
memset(path,0,MAX);
while(lenght=read(pipefd[0],path,MAX-1)){
printf("Data read so far %s\n", path);
if(send(sock,path,strlen(path),0) != strlen(path) ){
Die("Failed");
}
fflush(NULL);
printf("Data sent so far %s\n", path);
memset(path,0,MAX);
}
close(pipefd[0]);
//exit(1); removed so server will not terminate
}
else
{
printf("Error !\n");
exit(0);//
}
}
/*
if (strcmp (data, "exit")==0)
{
exit (1);
}
printf("Closing socket\n");
close(sock);
*/
}
int main(int argc, char const *argv[])
{
int serversock,clientsock;
struct sockaddr_in echoserver, echoclient;
unsigned int clientlen = sizeof(echoclient);
signal(SIGPIPE, SIG_IGN); // this will allow code to handle SIGPIPE instead of crashing
if((serversock = socket(PF_INET, SOCK_STREAM,IPPROTO_TCP))<0){
Die("Failed");
}
memset(&echoserver,0,sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr= htonl(INADDR_ANY);
echoserver.sin_port = htons(atoi(argv[1]));
if(bind(serversock, (struct sockaddr *) & echoserver,sizeof(echoserver))<0){
Die("Failed");
}
if(listen(serversock,MAXPENDING)<0){
Die("Failed");
}
while(1)
{
if((clientsock =
accept(serversock,(struct sockaddr *) &echoclient,
&clientlen))<0){
Die("Failed");
}
fprintf(stdout, "Client connected: %s\n",
inet_ntoa(echoclient.sin_addr));
fprintf(stdout,"Message from client:");
HandeClient(clientsock);
}
return 0;
}
<强>客户端强>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define BUFFSIZE 2048
void Die(char *mess)
{
perror(mess);
exit(1);
}
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in echoserver;
char buffer[BUFFSIZE];
unsigned int echolen;
int received = 0;
if (argc != 3)
{
fprintf(stderr, "USAGE: TCPecho <server_ip> <word> <port>\n");
exit(1);
}
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
Die("Failed to create socket");
}
memset(&echoserver, 0, sizeof(echoserver));
echoserver.sin_family = AF_INET;
echoserver.sin_addr.s_addr = inet_addr(argv[1]);
echoserver.sin_port = htons(atoi(argv[2]));
if (connect(sock,(struct sockaddr *) &echoserver,sizeof(echoserver)) < 0)
{
Die("Failed to connect with server");
}
char s[100];
while(1) { // to repeat the whole process until exit is typed
fgets(s,100,stdin);
s[strlen(s)-1]='\0'; //fgets doesn't automatically discard '\n'
echolen = strlen(s);
/* send() from client; */
if (send(sock, s, echolen, 0) != echolen)
{
Die("Mismatch in number of sent bytes");
}
if(strcmp(s,"exit") == 0) // check if exit is typed
exit(0);
fprintf(stdout, "Message from server: ");
while (received < echolen)
{
int bytes = 0;
/* recv() from server; */
if ((bytes = recv(sock, buffer, echolen, 0)) < 1)
{
Die("Failed to receive bytes from server");
}
received += bytes;
buffer[bytes] = '\0';
/* Assure null terminated string */
fprintf(stdout, buffer);
}
int bytes = 0;
// this d {...} while block will receive the buffer sent by server
do {
buffer[bytes] = '\0';
printf("%s\n", buffer);
} while((bytes = recv(sock, buffer, BUFFSIZE-1, 0))>=BUFFSIZE-1);
buffer[bytes] = '\0';
printf("%s\n", buffer);
printf("\n");
}
}
没有必要循环客户端,因为服务器在发回结果后退出。
答案 1 :(得分:0)
您在此行上遇到分段错误,因为您尝试将整数传递给strlen
:
write(STDOUT_FILENO,pipefd[1],strlen(pipefd[1]));
您的编译器应至少发出一个警告; gcc确实:
server.c:84: warning: passing argument 1 of 'strlen' makes pointer from integer without a cast
/usr/include/string.h:399: note: expected 'const char *' but argument is of type 'int'
如果打算将pipefd[1]
的值写为STDOUT_FILENO
作为二进制整数,那么您的意思是这样做吗?
write(STDOUT_FILENO,&pipefd[1],sizeof(pipefd[1]));