如何使用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;