Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用C套接字正确发送数据和管理进程_C_Sockets - Fatal编程技术网

如何使用C套接字正确发送数据和管理进程

如何使用C套接字正确发送数据和管理进程,c,sockets,C,Sockets,我正在尝试使用套接字构建一个简单的聊天室,但有一个问题我无法解决。套接字服务器可以接收任何客户端的数据,并且服务器还可以将数据发送回客户端。我的问题是,当我创建多个客户机时,新创建的客户机可以向服务器发送数据,服务器可以像我预期的那样向现有客户机发送数据,但如果现有客户机向服务器发送数据,而服务器向新创建的客户机发送数据,则无法正常工作。错误是错误的文件描述符。谁能帮帮我,谢谢 #define MSGSIZE 2048 #define CLIENTSIZE 2 typedef struc

我正在尝试使用套接字构建一个简单的聊天室,但有一个问题我无法解决。套接字服务器可以接收任何客户端的数据,并且服务器还可以将数据发送回客户端。我的问题是,当我创建多个客户机时,新创建的客户机可以向服务器发送数据,服务器可以像我预期的那样向现有客户机发送数据,但如果现有客户机向服务器发送数据,而服务器向新创建的客户机发送数据,则无法正常工作。错误是错误的文件描述符。谁能帮帮我,谢谢

#define MSGSIZE    2048
#define CLIENTSIZE 2

typedef struct {
    long _type;
    char _data[MSGSIZE];
} msgQueue;

typedef struct {
    int shmid;
    int writablePid;
    int childProcessSize;
    int clientSockfds[CLIENTSIZE];
} SockfdInShm;

void serverRun(void);
void childProcess(int sockfd, struct sockaddr_in addr);
void *threadDoSend(void *arg);
void *threadDoRecv(void *arg);
int msgQueueGet(void);
void updateShm(SockfdInShm *shmLinker, int pos);
SockfdInShm* sockfdInShmGet(void);

int main(void)
{
    serverRun();
    return 0;
}

void serverRun(void)
{
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int sockfd, _sockfd, addrlen, size;
    addrlen = sizeof(struct sockaddr); 

    msgQueue msg = {0};
    int msgid = msgQueueGet(); 

    //create socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd) {
        perror("Fail to create socket");
        exit(-1);
    }

    printf("The server is running...\n");
    //enable address reuse
    int on = 1;
    if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))){
        perror("setsockopt error");
        exit(-1);
    }

    //bind the socket with an IP
    memset(&server_addr, 0, addrlen);
    server_addr.sin_family      = AF_INET;
    server_addr.sin_port        = htons(1234);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(-1 == bind(sockfd, (struct sockaddr*)&server_addr, addrlen)){
        perror("bind error");
        exit(-1);
    }

    //listen the socket
    if(-1 == listen(sockfd, 20)){
        perror("listen error");
        exit(-1);
    } 

    int pos;
    char serverInput[128];
    pid_t pidChild;
    SockfdInShm *shmLinker = sockfdInShmGet();
    shmLinker->childProcessSize = 0;
    memset(&(shmLinker->clientSockfds), 0, sizeof(int)*CLIENTSIZE);
    while(1) {
        addrlen = sizeof(struct sockaddr); 
        _sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);

        pos = shmLinker->childProcessSize;
        shmLinker->clientSockfds[shmLinker->childProcessSize++] = _sockfd;

        pidChild = fork();
        if(pidChild < 0) {
            perror("fork error");
            close(_sockfd);
            continue;
        } else if(pidChild > 0) {
            //close(_sockfd);
            //fgets(serverInput, 128, stdin);
            //if(strcmp(serverInput, ".exit\n") == 0) break;
            continue;
        } else {
            printf("fork success, child pid: %d\n", getpid());
            close(sockfd);
            childProcess(_sockfd, client_addr);
            close(_sockfd);
            updateShm(shmLinker, pos);
            exit(0);
        }
    }

    close(sockfd);
    shmctl(shmLinker->shmid, IPC_RMID, 0); 
    printf("This server has been closed\n");
}

void childProcess(int sockfd, struct sockaddr_in addr)
{
    printf("IP:   %s\n", inet_ntoa(addr.sin_addr));
    printf("Port: %d\n", ntohs(addr.sin_port));

    pthread_t sendptid, recvptid;
    pthread_create(&sendptid, NULL, threadDoSend, &sockfd);
    pthread_create(&recvptid, NULL, threadDoRecv, &sockfd); 

    pthread_join(sendptid, NULL);
    pthread_join(recvptid, NULL);
}

void *threadDoSend(void *arg)
{
    msgQueue msg = {0};
    SockfdInShm *shmLinker = sockfdInShmGet();
    int sockfd = *(int *)arg;
    //create a unique key for msg queue
    int msgid = msgQueueGet();

    int j, r;
    while(1) {
        msg._type = sockfd; 
        memset(&msg._data, 0, MSGSIZE);
        msgrcv(msgid, &msg, MSGSIZE, msg._type, 0);
        if(strcmp(msg._data, ".exit\n") == 0) break;

        for(j=0; j<CLIENTSIZE; ++j) {
            if(shmLinker->clientSockfds[j] == 0 || shmLinker->clientSockfds[j] == sockfd) continue;
           // if(shmLinker->clientSockfds[j] == 0) continue;
            printf("send to sockfd %d\n", shmLinker->clientSockfds[j]);
            r = send(shmLinker->clientSockfds[j], msg._data, strlen(msg._data), 0);
            if(r==-1) perror("send");**//here the error occurs**
        }
    }
}

void *threadDoRecv(void *arg)
{
    msgQueue msg = {0};
    int sockfd = *(int *)arg;
    int msgid, flag;

    //create a unique key for msg queue
    msgid = msgQueueGet();   
    while(1) {
        memset(&msg._data, 0, MSGSIZE);
        recv(sockfd, msg._data, MSGSIZE, 0);
        msg._type = sockfd;
        flag = msgsnd(msgid, &msg, strlen(msg._data), 0);
        if(flag==-1) perror("msgsnd in threadDoRecv");

        if(strcmp(msg._data, ".exit\n") == 0) break;
        printf("%s\n", msg._data);
    }
}

int msgQueueGet(void)
{
    int mkey = ftok("/dev", 'a');
    if(mkey == -1) {
        perror("ftok");
        exit(-1);
    }

    int msgid = msgget(mkey, IPC_CREAT|0666);
    if(msgid == -1) {
        perror("msgget");
        exit(-1);
    }
    return msgid;
}

void updateShm(SockfdInShm *shmLinker, int pos)
{
    shmLinker->clientSockfds[pos] = 0;
    shmLinker->childProcessSize--;
    int i, j;
    for(i=0; i<CLIENTSIZE; ++i) {
        if(shmLinker->clientSockfds[i]) continue;
        for(j=i+1; j<CLIENTSIZE; ++j) {
           if(!shmLinker->clientSockfds[j]) continue;
           shmLinker->clientSockfds[i] = shmLinker->clientSockfds[j];
           shmLinker->clientSockfds[j] = 0;
           break;
        }
    }
}

SockfdInShm* sockfdInShmGet(void)
{
    int shmid;
    SockfdInShm *shmLinker = NULL;

    shmid = shmget((key_t)6638, sizeof(SockfdInShm), IPC_CREAT|0666);
    if(shmid == -1) {
        perror("shmid");
        exit(EXIT_FAILURE);
    }
    shmLinker = (SockfdInShm *)shmat(shmid, 0, 0);
    shmLinker->shmid = shmid;

    return shmLinker;
}
#定义MSGSIZE 2048
#定义客户端大小2
类型定义结构{
长型;
字符数据[MSGSIZE];
}msgQueue;
类型定义结构{
int shmid;
int可写pid;
int-childProcessSize;
int clientSockfds[CLIENTSIZE];
}SockfdInShm;
void服务器运行(void);
void childProcess(intsockfd,addr中的结构sockaddr_);
void*threadDoSend(void*arg);
void*threadDoRecv(void*arg);
int msgQueueGet(void);
void updateShm(SockfdInShm*shmLinker,int pos);
SockfdInShm*sockfdInShmGet(无效);
内部主(空)
{
serverRun();
返回0;
}
void服务器运行(void)
{
服务器地址中的结构sockaddr\u;
客户端地址中的结构sockaddr\u;
int sockfd,_sockfd,addrlen,尺寸;
addrlen=sizeof(结构sockaddr);
msgQueue msg={0};
int msgid=msgQueueGet();
//创建套接字
sockfd=套接字(AF_INET,SOCK_STREAM,0);
如果(-1==sockfd){
perror(“无法创建套接字”);
出口(-1);
}
printf(“服务器正在运行…\n”);
//启用地址重用
int on=1;
if(-1==setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))){
perror(“设置锁定选择错误”);
出口(-1);
}
//用IP绑定套接字
memset(&server\u addr,0,addrlen);
服务器地址sin家庭=AF网络;
服务器地址sin端口=htons(1234);
服务器地址sin地址s地址=htonl(INADDR\U ANY);
if(-1==bind(sockfd,(struct sockaddr*)和server_addr,addrlen)){
perror(“绑定错误”);
出口(-1);
}
//听插座
如果(-1==侦听(sockfd,20)){
perror(“侦听错误”);
出口(-1);
} 
int pos;
字符服务器输入[128];
pid_t pidChild;
SockfdInShm*shmLinker=sockfdInShmGet();
shmLinker->childProcessSize=0;
memset(&(shmLinker->clientSockfds),0,sizeof(int)*CLIENTSIZE;
而(1){
addrlen=sizeof(结构sockaddr);
_sockfd=accept(sockfd,(结构sockaddr*)和client_addr,&addrlen);
pos=shmLinker->childProcessSize;
shmLinker->clientSockfds[shmLinker->childProcessSize++]=\u sockfd;
pidChild=fork();
if(pidChild<0){
perror(“分叉错误”);
关闭(_sockfd);
继续;
}else if(pidChild>0){
//关闭(_sockfd);
//fgets(服务器输入,128,标准输入);
//如果(strcmp(serverInput,“.exit\n”)==0)中断;
继续;
}否则{
printf(“fork成功,子pid:%d\n”,getpid());
关闭(sockfd);
childProcess(客户地址);
关闭(_sockfd);
updateShm(shmLinker,pos);
出口(0);
}
}
关闭(sockfd);
shmctl(shmLinker->shmid,IPC\u RMID,0);
printf(“此服务器已关闭\n”);
}
void子进程(int-sockfd,addr中的结构sockaddr_)
{
printf(“IP:%s\n”,inet_ntoa(addr.sin_addr));
printf(“端口:%d\n”,ntohs(地址sin_端口));
pthread_t sendptid,recvptid;
pthread_create(&sendptid、NULL、threadDoSend和&sockfd);
pthread_create(&recvptid、NULL、threadDoRecv和&sockfd);
pthread_join(sendptid,NULL);
pthread_join(recvptid,NULL);
}
void*threadDoSend(void*arg)
{
msgQueue msg={0};
SockfdInShm*shmLinker=sockfdInShmGet();
int sockfd=*(int*)arg;
//为消息队列创建唯一密钥
int msgid=msgQueueGet();
int j,r;
而(1){
msg._type=sockfd;
memset(&msg.\u数据,0,MSGSIZE);
msgrcv(msgid,&msg,MSGSIZE,msg.\u类型,0);
如果(strcmp(msg._data,“.exit\n”)==0)中断;
对于(j=0;jclientSockfds[j]==0 | | shmLinker->clientSockfds[j]==sockfd)继续;
//如果(shmLinker->clientSockfds[j]==0)继续;
printf(“发送到sockfd%d\n”,shmLinker->clientSockfds[j]);
r=send(shmLinker->clientSockfds[j],msg.\u数据,strlen(msg.\u数据),0);
如果(r==-1)perror(“send”);**//则出现错误**
}
}
}
void*threadDoRecv(void*arg)
{
msgQueue msg={0};
int sockfd=*(int*)arg;
int msgid,标志;
//为消息队列创建唯一密钥
msgid=msgQueueGet();
而(1){
memset(&msg.\u数据,0,MSGSIZE);
recv(sockfd,msg.\u数据,MSGSIZE,0);
msg._type=sockfd;
flag=msgsnd(msgid,&msg,strlen(msg.\u数据),0);
if(flag==-1)perror(“线程中的msgsnd”);
如果(strcmp(msg._data,“.exit\n”)==0)中断;
printf(“%s\n”,msg.\u数据);
}
}
int msgQueueGet(无效)
{
int mkey=ftok(“/dev”,“a”);
如果(mkey==-1){
佩罗尔(“ftok”);
出口(-1);
}
int msgid=msgget(mkey,IPC|u CREAT | 0666);
如果(msgid==-1){
佩罗尔(“msgget”);
出口(-1);
}
返回msgid;
}
void updateShm(SockfdInShm*shmLinker,int pos)
{
shmLinker->clientSockfds[pos]=0;
shmLinker->childProcessSize--;
int i,j;
对于(i=0;iclientSockfds[i]),继续;
对于(j=i+1;jclientSockfds[j]),继续;
shmLinker->clientSockfds[i]=shmLinker->clientSockfds[j];
shmLinker->clientSockfds[j]=0;
打破
}
}
}
SockfdInShm*sockfdInShmGet(无效)
{
int shmid;
SockfdInShm*shmLinker=NULL;
shmid=shmget((键)6638,sizeof(SockfdInShm),IPC|u CREAT | 0666);
如果(shmid==-1){
佩罗尔(“shmid”);
退出(退出失败);
}
shmLinker=(SockfdInShm*)shmat(shmid,0,
pthread_create(&sendptid, NULL, threadDoSend, &sockfd);
pthread_create(&sendptid, NULL, threadDoSend, sockfd);
int sockfd = (int)arg;