C:“;所有客户端连接的相同文件描述符“;(客户机-服务器编程)
在每一个新的客户端连接上,分叉服务器进程 不同的进程(服务器的其他子进程,即exec)无法识别在分叉子进程中使用相同fd的客户端 如何在其他流程上区分客户端 如果文件描述符为new sockfd,则accept调用返回相同的值C:“;所有客户端连接的相同文件描述符“;(客户机-服务器编程),c,sockets,client-server,C,Sockets,Client Server,在每一个新的客户端连接上,分叉服务器进程 不同的进程(服务器的其他子进程,即exec)无法识别在分叉子进程中使用相同fd的客户端 如何在其他流程上区分客户端 如果文件描述符为new sockfd,则accept调用返回相同的值 /* server process */ #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h&g
/* server process */
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#define SIZE sizeof(struct sockaddr_in)
void catcher(int sig);
int newsockfd;
int main(void)
{
int sockfd;
char c;
struct sockaddr_in server = {AF_INET, 7000, INADDR_ANY};
static struct sigaction act;
act.sa_handler = catcher;
sigfillset(&(act.sa_mask));
sigaction(SIGPIPE, &act, NULL);
/* set up the transport end point */
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket call failed");
exit(1);
}
/* bind an address to the end point */
if ( bind(sockfd, (struct sockaddr *)&server, SIZE) == -1)
{
perror("bind call failed");
exit(1);
}
/* start listening for incoming connections */
if ( listen(sockfd, 5) == -1 )
{
perror("listen call failed");
exit(1) ;
}
for (;;)
{
/* accept a connection */
if ( (newsockfd = accept(sockfd, NULL, NULL)) == -1)
{
perror("accept call failed");
continue;
}
printf("New connection. File descriptor fd is %d\n",newsockfd);
/* spawn a child to deal with the connection */
if ( fork() == 0)
{
while (recv(newsockfd, &c, 1, 0) > 0)
{
c = toupper(c);
send(newsockfd, &c,1, 0);
}
/* when client is no longer sending information the socket can be closed and the child process terminated */
close(newsockfd);
exit (0);
}
/* parent doesn't need the newsockfd */
close(newsockfd);
}
}
void catcher(int sig)
{
close(newsockfd);
exit (0);
}
/* client process */
#include <ctype.h>
#include <sys/types.h>
#include<stdlib.h>
#include<stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SIZE sizeof(struct sockaddr_in)
int main(void)
{
int sockfd;
char c, rc;
struct sockaddr_in server = {AF_INET, 7000};
/* convert and store the server's IP address */
server.sin_addr.s_addr = inet_addr("127.0.0.1");
/* set up the transport end point */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket call failed");
exit(1);
}
/* connect the socket to the server's address */
if ( connect (sockfd, (struct sockaddr *)&server, SIZE) == -1)
{
perror("connect call failed");
exit(1);
}
/* send and receive information with the server */
for(rc = '\n';;)
{
if (rc == '\n')
printf("Input a lower case character\n");
c = getchar();
send(sockfd, &c, 1, 0);
if (recv(sockfd, &rc, 1, 0) >0)
printf("%c", rc);
else
{
printf("server has died\n");
close(sockfd);
exit(1);
}
}
}
/*服务器进程*/
#包括
#包括
#包括
#包括
#包括
#定义大小sizeof(结构sockaddr\u in)
空隙捕捉器(int sig);
int newsockfd;
内部主(空)
{
int-sockfd;
字符c;
服务器中的结构sockaddr_={AF_INET,7000,INADDR_ANY};
静态结构动作;
act.sa_handler=捕手;
sigfillset(&(act.sa_mask));
sigaction(SIGPIPE,&act,NULL);
/*设置传输端点*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))=-1)
{
perror(“套接字调用失败”);
出口(1);
}
/*将地址绑定到端点*/
if(绑定(sockfd,(结构sockaddr*)和服务器,大小)=-1)
{
perror(“绑定调用失败”);
出口(1);
}
/*开始侦听传入连接*/
如果(监听(sockfd,5)=-1)
{
perror(“监听呼叫失败”);
出口(1);
}
对于(;;)
{
/*接受连接*/
if((newsockfd=accept(sockfd,NULL,NULL))=-1)
{
perror(“接受呼叫失败”);
继续;
}
printf(“新连接。文件描述符fd为%d\n”,newsockfd);
/*生成一个子项以处理连接*/
如果(fork()==0)
{
而(recv(newsockfd,&c,1,0)>0)
{
c=toupper(c);
发送(newsockfd和c,1,0);
}
/*当客户端不再发送信息时,可以关闭套接字并终止子进程*/
关闭(newsockfd);
出口(0);
}
/*父级不需要newsockfd*/
关闭(newsockfd);
}
}
空隙捕捉器(内部信号)
{
关闭(newsockfd);
出口(0);
}
/*客户端进程*/
#包括
#包括
#包括
#包括
#包括
#包括
#定义大小sizeof(结构sockaddr\u in)
内部主(空)
{
int-sockfd;
字符c,rc;
服务器中的结构sockaddr_={AF_INET,7000};
/*转换并存储服务器的IP地址*/
server.sin_addr.s_addr=inet_addr(“127.0.0.1”);
/*设置传输端点*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))=-1)
{
perror(“套接字调用失败”);
出口(1);
}
/*将套接字连接到服务器的地址*/
if(连接(sockfd,(结构sockaddr*)和服务器,大小)=-1)
{
perror(“连接呼叫失败”);
出口(1);
}
/*使用服务器发送和接收信息*/
对于(rc='\n';)
{
如果(rc=='\n')
printf(“输入小写字符\n”);
c=getchar();
发送(sockfd和c,1,0);
如果(recv(sockfd和rc,1,0)>0)
printf(“%c”,rc);
其他的
{
printf(“服务器已死亡\n”);
关闭(sockfd);
出口(1);
}
}
}
文件描述符编号仅在其所在的进程中是唯一的,一旦关闭,就可以重新使用(例如下次调用accept
)。“连接标识符”不是一个好的选择
在每个连接都有一个新进程的情况下,连接最自然的标识符是进程id——但由于没有保存fork
的返回值,您已经将它丢弃了。在父进程中,fork
返回它创建的子进程的pid。您希望保存此文件并在以后使用。特别是,您可以使用它来终止子进程或识别子进程何时退出(wait
-家族函数将告诉您哪个子进程退出)
当然,如果您的整个模型对每个连接都使用单独的进程,我不确定为什么您需要在父进程中标识连接。如果每个连接不是一个完全独立的进程,那么使用线程而不是进程可能会做得更好。我希望服务器进程的子进程3能够向该客户端发送消息。在这种情况下,PID没有用处。主要代码如下:我应该使用哪个IPC来实现这个机制(子3可以向客户端发送消息)?