سلام به همه اساتید
(من تازه کارم) و میخوام یه برنامه چت سرور با سی توی لینوکس بنویسم
از کجا و با چی شروع کنم؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟ ؟؟؟؟؟؟؟؟؟؟؟؟
سلام به همه اساتید
(من تازه کارم) و میخوام یه برنامه چت سرور با سی توی لینوکس بنویسم
از کجا و با چی شروع کنم؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟ ؟؟؟؟؟؟؟؟؟؟؟؟
لازم به نوشتن نیست خیلی راحت قابل پیاده سازی هست
ممنون از پاسختون ولی چه جوری باید پیاده سازی بشه؟
در ضمن یه کتاب خوبم برا مطالعه روی شبکه های کلاینت سرور معرفی کنید
قبلا مچکرم........
ویرایش توسط vasighi : 2007-05-09 در ساعت 03:05 PM
میتونید از چت سرور های آماده مثل digi chat استفاده کنید.
نه من میخوام خودم بنویسم
چه کتاب یا مرجعی رو باید بخونم؟؟؟؟؟؟؟؟؟؟؟
asp dot net انتشارات microsoft press.
سلام
شما اگر C و مفاهیم شبکه رو به خوبی یاد گرفته باشید با یک مقاله ی کوچیک هم میشه نوشتن Chat Server رو یاد گرفت.من دو تا PDF برای برنامه نویسی شبکه تحت ویندوز براتون upload کردم که واقعاً عالی هستند و میتونید از ایـــنجــــا دانلودش کنید.
شاید بهتر باشه اول یک برنامه کوچیک بنویسید که فقط یک نفر بتونه با telnet یا Net Cat بهش وصل بشه و هر چیزی که تایپ میشه رو نمایش بده.تا اینجا که پیش رفتید بعد میتونید با تابع SELECT تعداد کلاینت های بیشتری رو پشتیبانی کنید و یک برنامه کلاینت ساده هم بنویسید.
آدرس error می ده
سلام
بله،مثل اینکه هاستم مشکل داره،شما فعلاً از ایـــنجـــا دانلودش کن تا یه فکری به حال اونجا بکنم!
دستتون درد نکنه
mishe lotfan bishtar rahnamaim konid
سلام
من این کد برنامه رو نوشتم( البته توی لینوکس) و وقتی با تلنت بهش وصل میشم با (هر چند تا کلاینت که میخوام )هر چیزی رو که روی یک کلاینت تایپ میکنم روی تمام کلاینت های دیگه هم نشون داده میشه .حالا میخوام مثل یه برنامه چت واقعی یه کلاینت بتونه طرف چت خودش رو انتخاب کنه نه اینکه multicast باشه.
و یه چیز دیگه...
میشه یه جوری نوشت که بدون تلنت کار کنه یعنی یه برنامه کلاینت بنویسم و به جای تلنت به سرور برنامه کلاینت رو اجرا کنم؟
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 9034 // port we’re listening on
int main(void)
{
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
struct sockaddr_in myaddr; // server address
struct sockaddr_in remoteaddr; // client address
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
char buf[256]; // buffer for client data
int nbytes;
int yes=1; // for setsockopt() SO_REUSEADDR, below
int addrlen;
int i, j;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get the listener
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
// lose the pesky "address already in use" error message
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
// bind
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = INADDR_ANY;
myaddr.sin_port = htons(PORT);
memset(&(myaddr.sin_zero), ’\0’, 8);
if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
perror("bind");
exit(1);
}
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(1);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it’s this one
// main loop
for(; {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(1);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof(remoteaddr);
if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr,
&addrlen)) == -1) {
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the maximum
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n", inet_ntoa(remoteaddr.sin_addr), newfd);
}
} else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i);
FD_CLR(i, &master); // remove from master set
} else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
}
}
}
}
return 0;
}
سلام
خوشم اومد
برای سئوال اول باید بگم برای اینکه بتونی مثلاً چند تا اتاق گفتگو داشته باشی باید یه منطقی برای برنامه تعریف کنی که چطور متوجه حضور یک کاربر در یک گفتگوی خاص بشه.چیزی که به نظر من رسید این هست که به صورت پیش فرض چهار پنج تا room تو برنامه تعریف کنی،بعد زمانی که کاربر مثل IRC با دستور Join اون روم رو انتخاب کرد از این به بعد یک بایت به اول همه ی پیام هایی که ارسال می کنه اضافه بشه که نشانه ی شماره ی اطاق گفتگو هست.زمانی که پیام های این کاربر به سرور میرسه اول بایت اول رو میخونی و بعد پیام رو برای کاربرای خاص اون اتاق گفتگو ارسال میکنی که قبلاً با دستور Join اعلام کردن که قصد ورود به چه اتاق گفتگویی رو دارن.
در واقع باید بشینی همه ی جوانب رو در نظر بگیری و یه پروتکل تعریف کنی.
در مورد سئوال دوم هم بله میشه یه برنامه ی جدا و اختصاصی طراحی کرد که من یه نمونش رو که جوونی هام نوشته بودم برات میذارم :
شما پروتکلت رو تعریف کن بعد همینجا کامل توضیح بده،من یه هفته / 10 روز کار دارم،بعد میتونیم بشینیم روش کار کنیم.چون آدم بد قولی هستم قولی نمیدم ولی سعی میکنم با هم تمومش کنیم،خودم هم خیلی وقته دلم برای اینجور کارا تنگ شده!کد:/*client.c--This is a Simple TCP Client.*/ #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #pragma comment(lib,"Ws2_32.lib") #define BUFFSIZE 1024 main(int argc,char **argv) { int bytes_sent,len; char buff[BUFFSIZE]; SOCKET connsocket; WSADATA wsadata; struct sockaddr_in server; if(WSAStartup(MAKEWORD(2,0),&wsadata) != 0) { printf("Windows Socket API Startup Failure.Exiting...\n"); exit(-1); } else if(LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 0) { printf("Windows Can not Provide Socket v2.0.Exiting...\n"); exit(-1); } connsocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr(argv[1]); printf("%d",atoi(argv[2])); server.sin_port = htons(atoi(argv[2])); if(connect(connsocket,(struct sockaddr *) &server,sizeof(struct sockaddr)) == 0) printf("Successfully Connected...\n Now You can Send Your Message to The" " Server.Type \"$\" sign to close the Connection.\n"); while(*buff != '$') { gets(buff); len = strlen(buff); bytes_sent = send(connsocket,buff,len,0); if(bytes_sent == SOCKET_ERROR) printf("Can not Send Data.\n"); else printf("%d Byte(s) Sent!\n",bytes_sent); } closesocket(connsocket); WSACleanup(); }
ویرایش توسط secure_krnl : 2007-07-29 در ساعت 01:18 PM علت: اشتباه تایپی
سلام
من این برنامه رو نوشتم ولی کار نمی کنه یعنیerror:segmentation error میده یعنی یه بار تا حدی کار کردا ولی وقتی سیستمم رو ریست کردم مدام همین پیغام رو میده بدون اینکه حتی وارد برنامه بشه...
برنامه کلاینت رو هم نوشتم
و یه چیز دیگه:میشه کامل برام کار تابعselect رو توضیح بدید و اینکه آیا برا اینکه سرور من بخواد چند تا لاینت رو پشتیبانی کنه باید حتما از این تابع استفاده کنم؟
کد HTML:#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/select.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <netdb.h> #define MYPORT 9000 #define BACKLOG 10 /*********************************************************/ struct UsersConnections; typedef struct UsersConnections UsersConnections; typedef UsersConnections *UsersConnectionsPTR; struct UsersConnections { int sockfd; char IP[16]; char *Nick; int Room; struct UsersConnections *Prev; struct UsersConnections *Next; }; UsersConnectionsPTR UsersConnectionsStart; /*********************************************************/ int ListenConnection(int port); void UsersConnectionsDelete(UsersConnectionsPTR *sPtr); UsersConnections *UsersConnectionsInsert(UsersConnectionsPTR *sPtr,int sFd,char*sIP,char *sNick); int CheckSocketRead(int sockfd); UsersConnections *UsersConnectionsInsert(UsersConnectionsPTR *sPtr,int sFd,char *sIP,char *sNick); int ReadClientData(UsersConnectionsPTR *sConnection); int CheckClientData(); int AcceptClient(int sockfd); int Quit(UsersConnectionsPTR *sConnection, char *sReason); /**********************************************************/ main() {printf("salam"); UsersConnectionsPTR Connection; Connection = UsersConnectionsStart; int sockfd,newfd,clientfd; struct sockaddr_in my_addr; struct sockaddr_in their_addr; int sin_size; UsersConnectionsStart = NULL; sockfd = ListenConnection(MYPORT); if(!(fork())){ sin_size=sizeof(struct sockaddr_in); // Check for new client connections while(1){ if (CheckSocketRead(sockfd) > 0) { // Accept the connection and add user to client list newfd=AcceptClient(sockfd); } //if(!fork()){ // Check for any incomming data from clients CheckClientData(); if(send(Connection->sockfd,"Hello World!\n",14,0)==-1) perror("send"); //close(newfd); Quit(&Connection,"Disconnected"); exit(0); while(waitpid(-1,NULL,WNOHANG)>0); } } //close(newfd); Quit(&Connection,"Disconnected"); } /*********************************************************/ int ListenConnection(int port) { int sockfd; struct sockaddr_in myaddr; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = INADDR_ANY; myaddr.sin_port = htons(port); memset(myaddr.sin_zero, 0, sizeof(myaddr.sin_zero)); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)) == -1) { perror("bind"); exit(1); } // This will listen to the port but we need another function to check this if (listen(sockfd,BACKLOG) == -1) { perror("listen"); exit(1); } return sockfd; } /*********************************************************/ int CheckSocketRead(int sockfd) { int rc; struct timeval tv; fd_set read_fd; tv.tv_sec=0; tv.tv_usec=1; FD_ZERO(&read_fd); FD_SET(sockfd, &read_fd); printf("salam"); rc = select(sockfd+1,&read_fd,NULL, NULL, &tv); if (rc>0) printf("salam"); FD_ZERO(&read_fd); return rc; } /*********************************************************/ int AcceptClient(int sockfd) { int newfd, sinsize; struct sockaddr_in clientaddr; UsersConnectionsPTR Connection; char nick[20]; sinsize = sizeof(struct sockaddr_in); newfd = accept(sockfd, (struct sockaddr *)&clientaddr, &sinsize); printf("%d",newfd); if (newfd == -1) { // you don't realy want to exit here as it's only 1 client that can't be accepted // however you will be required to investigate why accept returned -1 perror("accept"); exit(1); //continue; } else if (newfd) { printf("New CLIENT connection from IP %s on socket %d\n",inet_ntoa(clientaddr.sin_addr), newfd); //printf("Please enter your NickName:"); //gets(nick); // Enable non-blocking socket for select() //fcntl(newfd,F_SETFL,O_NONBLOCK); // Add user to connection list Connection=UsersConnectionsInsert(&UsersConnectionsStart,newfd,(char *)inet_ntoa(clientaddr.sin_addr),"nick"); } } /*********************************************************/ int CheckClientData() { int rc, max; struct timeval tv; UsersConnectionsPTR Connection, Next; char output[1024]; fd_set usersfd; tv.tv_sec=0; tv.tv_usec=0; Connection = UsersConnectionsStart; while (Connection != NULL) { Next = Connection->Next; FD_ZERO(&usersfd); FD_SET(Connection->sockfd, &usersfd); errno = 0; rc = select(Connection->sockfd+1,&usersfd ,NULL, NULL, &tv); if (rc > 0) { ReadClientData(&Connection); } else if (rc == -1) { sprintf(output,"%m\n",errno); Quit(&Connection, output); } Connection = Next; } } /*********************************************************/ int ReadClientData(UsersConnectionsPTR *sConnection) { int i, ch, rc; char data[1024], output[1024]; char buffer[1024]; UsersConnectionsPTR Connection; Connection = *sConnection; if(send(Connection->sockfd,"Hello World!\n",14,0)==-1) perror("send"); } /*********************************************************/ UsersConnections *UsersConnectionsInsert(UsersConnectionsPTR *sPtr,int sFd,char *sIP,char *sNick) { UsersConnectionsPTR newPtr, previousPtr, currentPtr, nextPtr; newPtr = (UsersConnections *) malloc(sizeof(UsersConnections)); if (newPtr != NULL) { newPtr->sockfd=sFd; strcpy(newPtr->IP, sIP); strcpy(newPtr->Nick,sNick); currentPtr = *sPtr; nextPtr = currentPtr->Next; newPtr->Next = currentPtr; newPtr->Prev = NULL; if (currentPtr != NULL) { currentPtr->Prev = newPtr; } *sPtr = newPtr; return newPtr; } else { printf("\n\nmalloc error: out of memory...\n\n"); return NULL; } } /*********************************************************/ int Quit(UsersConnectionsPTR *sConnection, char *sReason) { char buffer[1024]; UsersConnectionsPTR Connection; Connection = *sConnection; close(Connection->sockfd); UsersConnectionsDelete(&Connection); } /*********************************************************/ void UsersConnectionsDelete(UsersConnectionsPTR *sPtr) { UsersConnectionsPTR previousPtr, nextPtr, currentPtr, tempPtr; tempPtr = *sPtr; previousPtr = (*sPtr)->Prev; nextPtr = (*sPtr)->Next; if (previousPtr == NULL) { if (nextPtr != NULL) { *sPtr = nextPtr; (*sPtr)->Prev = NULL; } else { *sPtr = NULL; } } else { if (nextPtr != NULL) { previousPtr->Next = nextPtr; nextPtr->Prev = previousPtr; } else { previousPtr->Next = NULL; } } free(tempPtr); } /*********************************************************/ [LEFT]client side[/LEFT]کد HTML:[left]#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define PORT 9000 /* the port client will be connecting to */ #define MAXDATASIZE 100 /* max number of bytes we can get at once */ int main(int argc, char *argv[]) { int sockfd, numbytes; char buf[MAXDATASIZE]; struct hostent *he; struct sockaddr_in their_addr; /* connector's address information */ if (argc != 2) { fprintf(stderr,"usage: client hostname\n"); exit(1); } if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */ herror("gethostbyname"); exit(1); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } their_addr.sin_family = AF_INET; /* host byte order */ their_addr.sin_port = htons(PORT); /* short, network byte order */ their_addr.sin_addr = *((struct in_addr *)he-h_addr); bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */ if (connect(sockfd, (struct sockaddr *)&their_addr, \ sizeof(struct sockaddr)) == -1) { perror("connect"); exit(1); } if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1) { perror("recv"); exit(1); } buf[numbytes] = '\0'; printf("Received: %s",buf); close(sockfd); return 0; } [/left]
سلام
من دو برنامه کلاینت c.c وسرور chatserver.c را به همراه برنامه ای که از لیست پیوندی استفاده کرده را دارم و می خوام با استفاده از پروتکل خودم تغییراتی روی آنها بدم.
سمت سرور به این صورته که اول که سرور اجرا میشه ./chatserver) ) می تونه با چند کلاینت ارتباط برقرار کنه و پیامهایی رو که هر کلاینت می فرسته برای همه کلاینت های دیگه هم می فرسته .
و سمت کلاینت(./c 127.0.0.1 9000) اینطوریه که اولا هر کلاینت تا پیامی نفرسته هیچ پیامی دریافت نمی کنه .یعنی recv() به شرط send() امکان پذیر هست و به محض اینکه اولین پیام را فرستاد تمام پیامهایی را که دیگران فرستاده اند را دریافت می کند این ارتباط همچنان هست تا وقتی که یه پیام bye\n دریافت کنه اونوقت connection بسته میشه و برنامه کلاینت تموم میشه.
اما پروتکلی که من فکر کردم:
برنامه کلاینت به این صورته که هنگامی که کاربر میخواد به سرور کانکت بشه اسم خودش رو به عنوان آرگومان ورودی وارد میکنه( ./c 127.0.0.1 9000 myname) وبعد از connect()شدن این آرگومان را( به عنوان فیلد name استراکچر UsersConnections) به سرور میفرسته و سروربعد از accept() کردن آن کاربر, توسط تابع insert() آن را داخل فیلد name به همراه اطلاعات دیگه کاربر کانکت شده(sockfd,ip,.. )به لیست پیوندی اضافه میکنه.(یا داخل آرایه ای از استراکچر UsersConnections )
کد HTML:[//client side [msg.payload=argv[3]; [Send(clientsockfd,msg);
("تقریبا" برنامه سرور با استفاده از لیست پیوندی)
//server side
و سپس اسم کاربر تازه وارد را به همه کاربران آنلاین اعلام میکنه .((sendtoall(argv[3] is now connected)کد HTML:[left]#include <sys/time.h> #include <sys/select.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> [right] [/right][/left][right][/right] [left]#define PORT 9000 #define MAXDATASIZE 100 struct UsersConnections; typedef struct UsersConnections UsersConnections; typedef UsersConnections *UsersConnectionsPTR; // List of users connections to server struct UsersConnections { int sockfd; char IP[16]; char name[100]; struct UsersConnections *Prev; struct UsersConnections *Next; } UsersConnectionsPTR UsersConnectionsStart; **************************************************** int Quit(UsersConnectionsPTR *sConnection, char *sReason) { char buffer[1024]; //UsersPTR From; UsersConnectionsPTR Connection; Connection = *sConnection; //From = (*sConnection)->User; // close file descriptor close(Connection->sockfd); // Delete //UsersDelete(&From); // Delete connection UsersConnectionsDelete(&Connection); } ***************** void handle_signal(int signum) { // This will require you to research more on signal handling printf("SIGNAL %d\n", signum); if (signum == 11 || signum == 2) exit(0); } ******************** /*int CheckSocketWrite(int sockfd) { int rc; struct timeval tv; fd_set write_fd; tv.tv_sec=0; tv.tv_usec=1; FD_ZERO(&write_fd); FD_SET(sockfd, &write_fd); rc = select(sockfd+1, NULL, &write_fd, NULL, &tv); FD_ZERO(&write_fd); return rc; }*/ ********************* UsersConnections *UsersConnectionsInsert(UsersConnectionsPTR *sPtr,int sFd,char *sIP,char *sNick) { UsersConnectionsPTR newPtr, previousPtr, currentPtr, nextPtr; newPtr = (UsersConnections *) malloc(sizeof(UsersConnections)); if (newPtr != NULL) { newPtr->sockfd=sFd; strcpy(newPtr->IP, sIP); strcpy(newPtr->Nick,sNick); currentPtr = *sPtr; nextPtr = currentPtr->Next; newPtr->Next = currentPtr; newPtr->Prev = NULL; if (currentPtr != NULL) { currentPtr->Prev = newPtr; } *sPtr = newPtr; return newPtr; } else { printf("\n\nmalloc error: out of memory...\n\n"); return NULL; } } *********************** void UsersConnectionsDelete(UsersConnectionsPTR *sPtr) { UsersConnectionsPTR previousPtr, nextPtr, currentPtr, tempPtr; tempPtr = *sPtr; previousPtr = (*sPtr)->Prev; nextPtr = (*sPtr)->Next; if (previousPtr == NULL) { if (nextPtr != NULL) { *sPtr = nextPtr; (*sPtr)->Prev = NULL; } else { *sPtr = NULL; } } else { if (nextPtr != NULL) { previousPtr->Next = nextPtr; nextPtr->Prev = previousPtr; } else { previousPtr->Next = NULL; } } free(tempPtr); } ************************ UsersConnections *Search(UsersConnectionsPTR *sPtr,char *sNick) { UsersConnectionsPTR currentPtr; currentPtr=*sPtr; while (currentPtr != NULL) { if (strcasecmp(currentPtr->Nick,sNick) == 0) { return currentPtr; } currentPtr=currentPtr->Next; } return NULL; } ************************ /*List data in our linked list: void List(UsersConnectionsPTR *sPtr) { UsersConnectionsPTR currentPtr; printf("\n\nListing users\n\n"); currentPtr = *sPtr; while (currentPtr != NULL) { printf("Name: %s\n",currentPtr->name); currentPtr = currentPtr->Next; } }*/ **************************************************** int main() { int clientfd; pid_t pid; int rc, max; struct timeval tv; char output[1024]; fd_set usersfd; tv.tv_sec=0; tv.tv_usec=0; int newfd, sinsize, sockfd; struct sockaddr_in clientaddr; struct sockaddr_in myaddr; UsersConnectionsPTR Connection, Next; UsersConnectionsStart = NULL; signal(SIGSEGV,handle_signal); signal(SIGINT,handle_signal); signal(SIGUSR1,handle_signal); signal(SIGUSR2,handle_signal); signal(SIGPIPE,SIG_IGN); sinsize = sizeof(struct sockaddr_in); myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = INADDR_ANY; myaddr.sin_port = htons(PORT); memset(myaddr.sin_zero, 0, sizeof(myaddr.sin_zero)); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)) == -1) { perror("bind"); exit(1); } if (listen(sockfd, 100) == -1) { perror("listen"); exit(1); } if(!fork()) { while(1) { int rc; struct timeval tv; fd_set read_fd; tv.tv_sec=0; tv.tv_usec=1; FD_ZERO(&read_fd); FD_SET(sockfd, &read_fd); rc = select(sockfd+1, &read_fd, NULL, NULL, &tv); FD_ZERO(&read_fd); If(rc>0) newfd = accept(sockfd,(struct sockaddr *)&clientaddr,&sinsize); //sockfd:listen socket if (newfd == -1) { perror("accept"); exit(1); } else if (newfd) { printf("New CLIENT connection from IP %s on socket %d\n", inet_ntoa(clientaddr.sin_addr), newfd); fcntl(newfd,F_SETFL,O_NONBLOCK); Connection = UsersConnectionsStart; while (Connection != NULL) { Next = Connection->Next; FD_ZERO(&usersfd); FD_SET(Connection->sockfd, &usersfd); errno = 0; rc = select(Connection->sockfd+1, &usersfd, NULL, NULL, &tv); if (rc > 0) { recv(Connection->sockfd,msg,MAXDATASIZE,0); [right]nick=msg.payload;[/right][/left][right][/right] [left]// Add user to connection list Connection=UsersConnectionsInsert(&UsersConnectionsStart,newfd,(char*)inet_ntoa(clientaddr.sin_addr),nick); } else if (rc == -1) { sprintf(output,"%m\n",errno); Quit(&Connection, output); } Connection = Next; }// while (Connection != NULL) usleep(200); }// while(1) }//if }//main ******** [/left]
تو قسمت آخر تابع chatserver میتونیم به جای buff,nick که بالا تعریف شد (اسم کلاینت کانکت شده )را بگذاریم
کد HTML:[left].. .. .. .. .. .. .. .. if((nbytes=recv(i,buf,sizeof(buf),0))<=0) { if(nbytes==0) { printf("select server:socket %d hang up\n",i); } else{ perror("recv error"); } close(i); FD_CLR(i,&master); } else {for(j=0;j<=fdmax;j++) { if(FD_ISSET(j,&master)) {if(j!=listener&&j!=i) { if(send(j,strcat(buf,"is now connected\n",nbytes,0)==-1) {perror("send error"); .. .. .. …. .. .. .. .. .. .. [/left]و همینطور نام کاربران آنلاین رابرای کاربر تازه واردلیست میکندو براش میفرسته (با استفاده از تابع( list(UsersConnectionsPTR *user که روی لیست پیوندی اعمال میشه)(این تابع میتونه اینطوری تغییر کنه که بجای printf از sprintf استفاده کنه و اسم کاربرها رو داخل آرایه nick (که داخل تابع main تعریف شده) قرار بده
که فیلد payload خود پیام و sockfd آدرس گیرنده.کد HTML:[left][right]Char nick[][];[/right][/left][right][/right] [left][right] sprintf (nick,"%s",UsersConnections.name)[/right][/left][right][/right] و سپس این آرایه را به کلاینت بفرستدو کلاینت تک تک خانه های آرایه را چاپ کند [left][right]For(i=0;nick[i]!=NULL;i++)[/right][/left][right][/right] [left][right] Printf("%s is Online…", nick[i]);[/right][/left][right][/right] [left][right]*****************************[/right][/left][right][/right] حالا کاربر برای شروع گفتگو باید درخواست خود را به یکی از این کاربران آنلاین بفرستد پیامی که با دستورات recv() و send() ردوبدل میشه رو به صورت یه استراکچر به صورت زیر تعریف کنیم: [left][right]Struct msg {[/right][/left][right][/right] [left][right] char Payload[256]; [/right][/left][right][/right] [left][right] int sockfd;[/right][/left][right][/right] [left][right]} msg;[/right][/left][right][/right] [left][/left]
کلاینت نام طرف گفتگوی خودش رو(داخل فیلد payload استراکچر msg قرار می ده )و به سرور می فرسته و سرور یه سرچ روی لیست پیوندی روی این اسم انجام می ده تا آدرسش رو (UsersConnections.sockfd ) بدست بیاره .این میشه آدرس گیرنده .
حالا این آدرس گیرنده را داخل فیلد sockfdmsg. قرار میده و به کلاینت می فرسته و کلاینت پیام درخواست گفتگو را به سرور می فرسته( ضمن اینکه فیلد آدرس دارای آدرس گیرنده است )و سرور تو یه حلقه for() کلاینت های(سوکت های accept() شده) رو که برا ی دریافت پیام آماده اند ((select(read_fd) رو چک میکنه بعد تو همین حلقه Recv(selectsockfd,msg) رو انجام میده بعد از دریافت پیام (msg) آن را به آدرس گیرنده که داخل خود پیام هست می فرسته .Send(msg.sockfd, msg,);)
.این سرچ روی یه لیست پیوندی از استراکچر UsersConnections (که یه متغیر سراسری تعریف شده و هر وقت سرور یه کلاینت جدید رو accept() می کنه اونو به این لیست insert() میکنه)انجام میشه که به صورت زیر تعریف شده:
<DIV align=left>کد HTML:[left][font=Tahoma][left]struct UsersConnections {[/left][/font][left] [font=Tahoma]int sockfd;[/font] [font=Tahoma]char IP[16];[/font] [font=Tahoma]char name[100];[/font] [font=Tahoma]struct UsersConnections *Prev;[/font] [font=Tahoma]struct UsersConnections *Next;[/font] [font=Tahoma]} UsersConnectionsPTR UsersConnectionsStart[/font][/left][font=Tahoma][/font][/left]
گفتگو تا وقتی ادامه دارد که یکی از طرفین کاراکتر$ را وارد کند آنگاه دوباره به کاربر اجازه ایجاد گفتگوی جدید با فراخوانی تابع talk() داده می شود.
و اگر کاربر کلمه quit را وارد کند آنگاه disconnect می شود(close(clientsockfd) در سمت سرور سوکت مربوط به کلاینتی که پیام quit را فرستاده می بندد)
در واقع کد سمت کلاینت بعد از connect() برای گفتگو باید به صورت زیر باشه :
......................
برنامه سمت کلاینت(c.c )کد HTML://chatserver [left]#include <stdio.h> برنامه سمت سرور : [left]#include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h>[/left] [left]#define PORT 9000 int main(void) { fd_set master; fd_set read_fds; struct sockaddr_in myaddr; struct sockaddr_in remoteaddr; int fdmax; int listener; int newfd; char buf[256]; int nbytes; int yes=1; int addrlen; int i,j; FD_ZERO(&master); FD_ZERO(&read_fds);[/left] [left]if((listener=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); exit(1); } if(setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1) { perror("setsockopt"); exit(1); } myaddr.sin_family=AF_INET; myaddr.sin_addr.s_addr=INADDR_ANY; myaddr.sin_port=htons(PORT);[/left] [left]memset(&(myaddr.sin_zero),'\0',8);[/left] [left]if(bind(listener,(struct sockaddr *)&myaddr,sizeof(myaddr))==-1) { perror("bind error"); exit(1); } if(listen(listener,10)==-1) { perror("listen error"); exit(1); } FD_SET(listener,&master); fdmax=listener;[/left] [left]for(;;) { read_fds=master; if(select(fdmax+1,&read_fds,NULL,NULL,NULL)==-1) { perror("select error"); exit(1); } for(i=0;i<=fdmax;i++) { if(FD_ISSET(i,&read_fds)) {if(i==listener) {addrlen=sizeof(remoteaddr); if((newfd=accept(listener,(struct sockaddr *)&remoteaddr,&addrlen))==-1) perror("accept error"); else{ FD_SET(newfd,&master); if(newfd>fdmax) fdmax=newfd; printf("select server:new connection from %s on socket %d\n",inet_ntoa(remoteaddr.sin_addr),newfd); } } else {if((nbytes=recv(i,buf,sizeof(buf),0))<=0) { if(nbytes==0) { printf("select server:socket %d hang up\n",i); } else{ perror("recv error"); } close(i); FD_CLR(i,&master); } else {for(j=0;j<=fdmax;j++) { if(FD_ISSET(j,&master)) {if(j!=listener&&j!=i) { if(send(j,buf,nbytes,0)==-1) {perror("send error"); } } } } } } } } }[/left] } [/left]
کد HTML:[left]/*client*/ [left]#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sockfd, portno, n; struct sockaddr_in serv_addr; struct hostent *server; char buffer[256]; if (argc < 3) { fprintf(stderr,"usage %s hostname port\n", argv[0]); exit(0); } portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); server = gethostbyname(argv[1]); if (server == NULL) { fprintf(stderr,"ERROR, no such host\n"); exit(0); } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) < 0) error("ERROR connecting"); //start of chat bzero(buffer,256); while(strcasecmp(buffer,"bye")!=0) { bzero(buffer,256); printf("Please enter the message: "); fgets(buffer,255,stdin); n = write(sockfd,buffer,strlen(buffer)); if (n < 0) error("ERROR writing to socket"); bzero(buffer,256); n = read(sockfd,buffer,255); if (n < 0) error("ERROR reading from socket"); printf("Here is the message: %s\n",buffer); }//while } [/left][/left]