早些时候,我对Client/server sockets in c提出了一些很好的建议。我稍微修改了代码,当我在一个终端中运行服务器并且客户端在其他窗口中运行时,它工作正常。现在我想为该程序制作一个TUI,但我遇到了一个问题。由于服务器一直在监听客户端,因此它处于无限循环中;一旦服务器建立,其他任何东西都不能在终端中继续。我认为我应该做的是使用fork(),以便服务器可以在后台运行,让TUI可以自由创建客户端。到目前为止,这是我的代码(同样,我不能为客户端/服务器代码付出太多代价):
服务器代码
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
struct sockaddr myname;
char buf[80];
ssize_t readLine(int sockd, char *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *buffer;
buffer = vptr;
for(n = 1; n < maxlen; n++) {
if((rc = read(sockd, &c, 1)) == 1) {
*buffer++ = c;
if(c== '\n')
break;
}
else if(rc == 0){
if(n == 1)
return 0;
else
break;
}
else {
if(errno == EINTR)
continue;
return -1;
}
}
*buffer = 0;
return n;
}
ssize_t modifyBuf(int sockd, char *vptr, size_t n) {
int i, j;
char temp;
for(i = 0, j = n-1; i < j; i++, j--) {
temp = vptr[i];
vptr[i] = vptr[j];
vptr[j] = temp;
}
for(i = 0; i < n; i++)
vptr[i] = toupper(vptr[i]);
return writeLine(sockd,vptr,n);
}
ssize_t writeLine(int sockd, const void *vptr, size_t n) {
size_t nleft;
size_t nwritten;
const char *buffer;
buffer = vptr;
nleft = n;
while(nleft > 0) {
if((nwritten = write(sockd,buffer,nleft)) <= 0){
if(errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
buffer += nwritten;
}
return n;
}
makeServer() {
int sock, new_sd, adrlen, cnt;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
printf("server socket failure %d\n", errno);
perror("server: ");
exit(1);
}
myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);
unlink("/tmp/billb"); /*defensive programming */
if(bind(sock, &myname, adrlen) < 0) {
printf("server bind failure%d\n", errno);
perror("server: ");
exit(1);
}
if(listen(sock, 5) < 0) {
printf("server listen failure %d\n", errno);
perror("server: ");
exit(1);
}
while(1) {
if((new_sd = accept(sock, &myname, &adrlen)) < 0) {
printf("server accept failure %d\n", errno);
perror("server: ");
exit(1);
}
printf("Socket address in server %d\n", getpid());
if(fork() == 0) {
close(sock);
readLine(new_sd,buf,999);
modifyBuf(new_sd,buf,strlen(buf));
exit(0);
}
close(new_sd);
}
}
客户代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
char buf[80];
struct sockaddr myname;
void replyBack(FILE *fp, int sockfd) {
char sendline[1000], recvline[1000];
printf("Enter your echo: \n");
while(fgets(sendline,1000,stdin) != NULL) {
write(sockfd,sendline,sizeof(sendline));
if(read(sockfd,recvline,1000) == 0) {
printf("str_cli: server terminated prematurely");
exit(-1);
}
fputs(recvline, stdout);
}
}
makeClient() {
int sock, adrlen, cnt;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
printf("client socket failure%d\n", errno);
printf("client: ");
exit(1);
}
myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);
if((connect(sock, &myname, adrlen)) < 0) {
printf("client connect failure %d\n", errno);
perror("client: ");
exit(1);
}
replyBack(stdin,sock);
exit(0);
}
TUI
#include <stdio.h>
#include </server.c>
#include </client.c>
void displayWelcomeMessage(){
....
}
void showChoices(){
printf("\nTo make a new client, enter 1.\n");
printf("To close server, enter 2.\n");
printf(">>> ");
int choice;
scanf("%d",&choice);
if(choice == 1){
makeClient();
showChoices();
} else if(choice == 2){
printf("Goodbye.");
exit(0);
} else
printf("Invalid choice.\n");
showChoices();
}
void main() {
displayWelcomeMessage();
printf("Server is now listening for clients.\n");
if(fork() == 0)
makeServer();
if(fork() > 0)
showChoices();
}
TUI 应在执行时创建服务器,然后显示一个简短的菜单。用户可以选择创建新客户端或退出程序。如果用户创建了客户端,则应提示用户输入要发送给服务器的消息;一旦消息被发回,菜单应该再次显示。如果用户选择退出程序,则程序将终止并且套接字应该关闭。如果用户选择无效,则菜单应再次显示。
正在发生的事情是服务器已创建,我可以看到菜单,但是如果我选择创建新客户端,程序会在我输入任何文本+输入后终止或终止(因此消息不会被发送到服务器)。就像我说的那样,客户端/服务器在没有TUI的情况下工作,所以我认为问题在于我使用fork(),但我不确定还有什么方法可以解决这个问题。
P,这很长。谢谢你的时间!答案 0 :(得分:1)
你似乎两次调用fork() - 当然你只想调用一次?我认为你的代码应该是:
if(fork() == 0)
makeServer();
else
showChoices();
此外,您可能想要调查wait()的使用,这将允许您等待子进程完成。