i see many people while trying to figure out winsock and networking often find basic blocking sockets easy to comprehend, but then get hopelessly stuck when it comes to using select(). now, this source code i wrote might not answer all the questions, but it at least has everything needed in a select server, and tries to explain what's happening. this program is a chat program, where multiple people can telnet in and see eachothers' messages:
by the way, if anyone has any suggestions on improving the code, feel free.Code://select example // by Steven Mills // n3v@comcast.net // Tested and compiled on dev c++. Compatibility with other compliers // can't be guaranteed. // use library ws2_32.lib with this project #include <iostream> #include <winsock2.h> using namespace std; // *** DECLARATIONS *** // const int PORT = 80; // this is the port the server runs on const int ireqver = 2; // required version of winsock on the machine running the server fd_set master; // master file descriptor list fd_set read_fds; // temp file descriptor list for select() struct sockaddr_in myaddr; //local machine's ip struct sockaddr_in remoteaddr; //client ip int fdmax; // maximum file descriptor number int newfd; //newly accept()ed socket discriptor char buf[256]; //buffer for client data int nbytes; int addrlen; int i, j; WSADATA wsaData; char welcome[] = {"Welcome! \n Chat program 1.0 by Steven Mills \n"}; /// *** MAIN PROGRAM *** /// int main(int argc, char *argv[]) { FD_ZERO(&master); // clear the master FD_ZERO(&read_fds); // and temp sets cout << "initiating winsock..."; if (WSAStartup(MAKEWORD(ireqver, 0), &wsaData) == 0) // checking winsock version { if (LOBYTE(wsaData.wVersion) >= ireqver) // is version good enough? { cout << "initiated." << endl; // yes } } else { cout << "requested version not available." << endl; // no } //set up the listening socket! cout << "setting up listening socket..."; SOCKET listener; // listening socket listener = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // defining the socket // PF_INET is the domain, or Protocol Family i selected. // You can also use AF_INET (Adress Family) for some reason, // the program works with both values, anyway, just remember // that you have to have this, because in these families is where // the TCP/IP and UDP connections are. // SOCK_STREAM indicates that we are using streaming sockets (TCP), and not a // datagram (UDP, or in the code it would be SOCK_DGRAM) // type of socket, which means that the bits in our SOCK_STREAM socket will get there // in the same order that they left. Datagram sockets are not suitable, for this // program, as they are for speed and not accuracy. They are better used in things like // streaming audio and video. // IPPROTO_TCP, or TCP/IP Protocol. see it? myaddr.sin_family = AF_INET; // assigning address family myaddr.sin_addr.s_addr = INADDR_ANY; // telling the server to accept any ip myaddr.sin_port = htons(PORT); // but only on this particular port memset(&(myaddr.sin_zero), '\0', 8); if (listener == SOCKET_ERROR) { // check for errors cout << "failed." << endl; } else if (bind(listener, (struct sockaddr *) &myaddr, sizeof(myaddr)) != 0) { cout << "failed" << endl; } // starting the listening! if (listen(listener, 10) != 0) { // a value of non-zero indicates an error cout << "failed"; } else { cout << "success." << endl; } //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) { // select will handle // the list of connections in the file descriptor cout << "error with select"; // error checking } // this following loop goes through the existing connections // looking for data to read, or new connections. for (i = 0; i <= fdmax; i++) { if (FD_ISSET(i, &read_fds)) { // NEW CONNECTION if (i == listener) { // handle new connection addrlen = sizeof(remoteaddr); if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen)) == -1) { // accepts new connection cout << "error processing new connection"; // error checking } else { FD_SET(newfd, &master); //add to master set if (newfd > fdmax) {// keeping track of maximum fdmax = newfd; } cout << "New connection from: " << inet_ntoa(remoteaddr.sin_addr) << " on socket " << newfd << "." << endl; // this identifies the connection if (send(newfd, welcome, sizeof(welcome), 0) == -1) { // sends the user // a welcome message when they connect to the server cout << "error while sending welcome message" << endl; // error checking } } } else { // handle data from a client if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { // error or connection terminated by client if (nbytes == 0) { //indicates that the client disconnected //connection closed cout << "socket " << i << " disconnected" << endl; } else { cout << "error recieving data" << endl; // error checking } closesocket(i); // socket closed FD_CLR(i, &master); // remove from master set } else { // real data from client for (j = 0; j <= fdmax; j++) { // send to every client if (FD_ISSET(j, &master)) { // except the listener and ourselves if (j != listener && j != i) { if (send(j, buf, nbytes, 0) == -1) { cout << "error while sending" << endl; // error checking } } } } } } } } } if (WSACleanup() != 0) { // have to clean up your winsock mess! cout << "cleanup failed." << endl; // error checking } system("PAUSE"); // you can use these last two lines if you want return EXIT_SUCCESS; }



LinkBack URL
About LinkBacks


