/*
Initialise Winsock
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
printf
(
"\n初始化中Initialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"初始化成功Initialised."
);
return
0;
}
winsock函數包含在winsock2.H。你還需要link ws2_32.lib到你的程序以便使用這些函數。
WSAStartup函數用於啟動或者初始化winsock庫。它需要兩個參數,第一個指定我們想要加載的版本,第二個是一個WSADATA結構體,它可以在winsock加載之後儲存額外的數據。
如果有錯誤產生的話,WSAStartup會返回一個非零值。並且可以用WSAGetLastError 來獲取更多信息。
好了,下一步就來創建一個socket。
socket()
函數來創建一個socket,示例代碼:/*
Create a TCP socket
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s;
printf
(
"\n初始化Initialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"失敗Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
if
((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"創建失敗Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"成功Socket created.\n"
);
return
0;
}
socket()
用於函數創建socket並且返回一個socket描述符,該描述符可以在其他網絡命令中使用,上述代碼將會創建像下面這樣的socket:
Address Family : AF_INET 表示IPv4
Type : SOCK_STREAM 面向TCP協議的
Protocol : 0 [ or IPPROTO_TCP , IPPROTO_UDP ]
/*
Create a TCP socket
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s;
struct
sockaddr_in server;
char
*message;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"Socket created.\n"
);
server.sin_addr.s_addr = inet_addr(
"74.125.235.20"
);
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if
(connect(s , (
struct
sockaddr *)&server ,
sizeof
(server)) < 0)
{
puts
(
"connect error"
);
return
1;
}
puts
(
"Connected"
);
//Send some data
message =
"GET / HTTP/1.1\r\n\r\n"
;
if
( send(s , message ,
strlen
(message) , 0) < 0)
{
puts
(
"Send failed"
);
return
1;
}
puts
(
"Data Send\n"
);
return
0;
}
/*
Create a TCP socket
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s;
struct
sockaddr_in server;
char
*message , server_reply[2000];
int
recv_size;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"Socket created.\n"
);
server.sin_addr.s_addr = inet_addr(
"74.125.235.20"
);
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if
(connect(s , (
struct
sockaddr *)&server ,
sizeof
(server)) < 0)
{
puts
(
"connect error"
);
return
1;
}
puts
(
"Connected"
);
//Send some data發送請求
message =
"GET / HTTP/1.1\r\n\r\n"
;
if
( send(s , message ,
strlen
(message) , 0) < 0)
{
puts
(
"Send failed"
);
return
1;
}
puts
(
"Data Send\n"
);
//Receive a reply from the server接收html文檔
if
((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts
(
"recv failed"
);
}
puts
(
"Reply received\n"
);
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] =
'\0'
;
puts
(server_reply);
return
0;
}
一下是上面代碼的輸出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Initialising Winsock...Initialised.
Socket created.
Connected已連接
Data Send數據已發送
Reply received已收到
HTTP
/1
.1 302 Found
Location: http:
//www
.google.co.
in
/
Cache-Control: private
Content-Type: text
/html
; charset=UTF-8
Set-Cookie: PREF=ID=7da819edfd7af808:FF=0:TM=1324882923:LM=1324882923:S=PdlMu0TE
E3QKrmdB; expires=Wed, 25-Dec-2013 07:02:03 GMT; path=/; domain=.google.com
Date: Mon, 26 Dec 2011 07:02:03 GMT
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
<HTML>
<HEAD>
<meta http-equiv=
"content-type"
content=
"text/html;
charset=utf-8
"
>
<TITLE>302 Moved<
/TITLE
>
<
/HEAD
>
<BODY>
<H1>302 Moved<
/H1
>
The document has moved
<A HREF=
"http://www.google.co.in/"
>here<
/A
>.
<
/BODY
><
/HTML
>
Press any key to
continue按任意鍵繼續
我們可以看到google.com返回的數據,它看起來好像是html,是的那就是html。google返回了我們想要的數據,太簡單啦!
現在我們已經收到了我們的數據,現在我們該關掉socket了。
closesocket(s);
WSACleanup();
.就是這些
gethostbyname
就是用來獲取ip的。它使用域名作為參數並且返回一個hostent結構體,該結構體包含ip信息。該結構體包含於netdb.h中,結構如下:
注意/* Description of data base entry for a single host. */
struct
hostent
{
char
*h_name;
/* Official name of host.
官方主機名*/
char
**h_aliases;
/* Alias list. 別名列表*/
int
h_addrtype;
/* Host address type. 主機地址類型*/
int
h_length;
/* Length of address. 地址長度*/
char
**h_addr_list;
/* List of addresses from name server. 主機地址列表 */
};
h_addr_list
包含ip地址,如下代碼演示如何獲取地址。
/*
Get IP address from domain name
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
char
*hostname =
"www.google.com"
;
char
ip[100];
struct
hostent *hostEntry;
struct
in_addr **addr_list;
int
i;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
if
( (
hostEntry =
gethostbyname
( hostname ) ) == NULL)
{
//gethostbyname failed
printf
(
"gethostbyname failed : %d"
, WSAGetLastError());
return
1;
}
//Cast the h_addr_list to in_addr , since h_addr_list also has the ip address in long format only
addr_list = (
struct
in_addr **)
hostEntry->h_addr_list;
for
(i = 0; addr_list[i] != NULL; i++)
{
//Return the first one;
strcpy
(ip , inet_ntoa(*addr_list[i]) );
}
printf
(
"%s resolved to : %s\n"
, hostname , ip);
return
0;
return
0;
}
代碼輸出如下
1www.google.com resolved to : 74.125.235.20
h_addr_list
可以把長地址轉換成點分地址。
1. 打開socket
2. 綁定到一個地址和端口
3. Listen 監聽進來的連接
4. Accept 接受連接
5. Read/Send讀取數據/發送數據
We have already learnt how to open a socket. So the next thing would be to bind it.
Function bind
can be used to bind a socket to a particular address and port. It needs a sockaddr_in structure similar to connect function.
Lets see a code example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49/*
Bind socket to port 8888 on localhost
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s;
struct
sockaddr_in server
;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"Socket created.\n"
);
//Prepare the sockaddr_in structure
server
.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server
.sin_port = htons( 8888 );
//Bind
if
(
bind
(s ,(
struct
sockaddr *)&server ,
sizeof
(server)) == SOCKET_ERROR)
{
printf
(
"Bind failed with error code : %d"
, WSAGetLastError());
}
puts
(
"Bind done"
);
closesocket(s);
return
0;
}
Now that bind is done, its time to make the socket listen to connections. We bind a socket to a particular IP address and a certain port number. By doing this we ensure that all incoming data which is directed towards this port number is received by this application.
This makes it obvious that you cannot have 2 sockets bound to the same port.
After binding a socket to a port the next thing we need to do is listen for connections. For this we need to put the socket in listening mode. Function listen
is used to put the socket in listening mode. Just add the following line after bind.
//Listen
listen(s , 3);
Thats all. Now comes the main part of accepting new connections.
Function accept
is used for this. Here is the code
/*
Bind socket to port 8888 on localhost
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s , new_socket;
struct
sockaddr_in server , client;
int
c;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((s =
socket
(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"Socket created.\n"
);
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if
(
bind
(s ,(
struct
sockaddr *)&server ,
sizeof
(server)) == SOCKET_ERROR)
{
printf
(
"Bind failed with error code : %d"
, WSAGetLastError());
}
puts
(
"Bind done"
);
//Listen to incoming connections
listen
(s , 3);
//Accept and incoming connection
puts
(
"Waiting for incoming connections..."
);
c =
sizeof
(
struct
sockaddr_in);
new_socket = accept(s , (
struct
sockaddr *)&client, &c);
if
(new_socket == INVALID_SOCKET)
{
printf
(
"accept failed with error code : %d"
, WSAGetLastError());
}
puts
(
"Connection accepted"
);
closesocket(s);
WSACleanup();
return
0;
}
Output
Run the program. It should show
1 2 3 4Initialising Winsock...Initialised.
Socket created.
Bind
done
Waiting
for
incoming connections...
So now this program is waiting for incoming connections on port 8888. Dont close this program , keep it running.
Now a client can connect to it on this port. We shall use the telnet client for testing this. Open a terminal and type
telnet localhost 8888
And the server output will show
1 2 3 4 5 6Initialising Winsock...Initialised.
Socket created.
Bind
done
Waiting
for
incoming connections...
Connection accepted
Press any key to
continue
So we can see that the client connected to the server. Try the above process till you get it perfect.
Note
You can get the ip address of client and the port of connection by using the sockaddr_in structure passed to accept function. It is very simple :
1 2char
*client_ip = inet_ntoa(client.sin_addr);
int
client_port = ntohs(client.sin_port);
We accepted an incoming connection but closed it immediately. This was not very productive. There are lots of things that can be done after an incoming connection is established. Afterall the connection was established for the purpose of communication. So lets reply to the client.
Here is an example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73/*
Bind socket to port 8888 on localhost
*/
#include<io.h>
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s , new_socket;
struct
sockaddr_in server , client;
int
c;
char
*message;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((s =
socket
(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"Socket created.\n"
);
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if
(
bind
(s ,(
struct
sockaddr *)&server ,
sizeof
(server)) == SOCKET_ERROR)
{
printf
(
"Bind failed with error code : %d"
, WSAGetLastError());
}
puts
(
"Bind done"
);
//Listen to incoming connections
listen(s , 3);
//Accept and incoming connection
puts
(
"Waiting for incoming connections..."
);
c =
sizeof
(
struct
sockaddr_in);
new_socket = accept(s , (
struct
sockaddr *)&client, &c);
if
(new_socket == INVALID_SOCKET)
{
printf
(
"accept failed with error code : %d"
, WSAGetLastError());
}
puts
(
"Connection accepted"
);
//Reply to client
message =
"Hello Client , I have received your connection. But I have to go now, bye\n"
;
send(new_socket , message ,
strlen
(message) , 0);
getchar
();
closesocket(s);
WSACleanup();
return
0;
}
Run the above code in 1 terminal. And connect to this server using telnet from another terminal and you should see this :
1Hello Client , I have received your connection. But I have to go now, bye
So the client(telnet) received a reply from server. We had to use a getchar because otherwise the output would scroll out of the client terminal without waiting
We can see that the connection is closed immediately after that simply because the server program ends after accepting and sending reply. A server like www.google.com is always up to accept incoming connections.
It means that a server is supposed to be running all the time. Afterall its a server meant to serve. So we need to keep our server RUNNING non-stop. The simplest way to do this is to put the accept
in a loop so that it can receive incoming connections all the time.
So a live server will be alive for all time. Lets code this up :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76/*
Live Server on port 8888
*/
#include<io.h>
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET s , new_socket;
struct
sockaddr_in server , client;
int
c;
char
*message;
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
return
1;
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
}
printf
(
"Socket created.\n"
);
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if
( bind(s ,(
struct
sockaddr *)&server ,
sizeof
(server)) == SOCKET_ERROR)
{
printf
(
"Bind failed with error code : %d"
, WSAGetLastError());
exit
(EXIT_FAILURE);
}
puts
(
"Bind done"
);
//Listen to incoming connections
listen(s , 3);
//Accept and incoming connection
puts
(
"Waiting for incoming connections..."
);
c =
sizeof
(
struct
sockaddr_in);
while
( (new_socket = accept(s , (
struct
sockaddr *)&client, &c)) != INVALID_SOCKET )
{
puts
(
"Connection accepted"
);
//Reply to the client
message =
"Hello Client , I have received your connection. But I have to go now, bye\n"
;
send(new_socket , message ,
strlen
(message) , 0);
}
if
(new_socket == INVALID_SOCKET)
{
printf
(
"accept failed with error code : %d"
, WSAGetLastError());
return
1;
}
closesocket(s);
WSACleanup();
return
0;
}
We havent done a lot there. Just the accept was put in a loop.
Now run the program in 1 terminal , and open 3 other terminals. From each of the 3 terminal do a telnet to the server port.
Run telnet like this
1C:\>telnet
1
2
3
Welcome to Microsoft Telnet Client
Escape Character is
'CTRL+]'
Microsoft Telnet>
open
localhost 8888
1
Hello Client , I have received your connection. But I have to go now, bye
And the server terminal would show
1 2 3 4 5 6Initialising Winsock...Initialised.
Socket created.
Bind
done
Waiting
for
incoming connections...
Connection accepted
Connection accepted
So now the server is running nonstop and the telnet terminals are also connected nonstop. Now close the server program.
All telnet terminals would show "Connection to host lost."
Good so far. But still there is not effective communication between the server and the client.
The server program accepts connections in a loop and just send them a reply, after that it does nothing with them. Also it is not able to handle more than 1 connection at a time. So now its time to handle the connections , and handle multiple connections together.
To handle every connection we need a separate handling code to run along with the main server accepting connections.
One way to achieve this is using threads. The main server program accepts a connection and creates a new thread to handle communication for the connection, and then the server goes back to accept more connections.
We shall now use threads to create handlers for each connection the server accepts. Lets do it pal.
1Run the above server and open 3 terminals like before. Now the server will create a thread for each client connecting to it.
The telnet terminals would show :
1This one looks good , but the communication handler is also quite dumb. After the greeting it terminates. It should stay alive and keep communicating with the client.
One way to do this is by making the connection handler wait for some message from a client as long as the client is connected. If the client disconnects , the connection handler ends.
So the connection handler can be rewritten like this :
1The above connection handler takes some input from the client and replies back with the same. Simple! Here is how the telnet output might look
1So now we have a server thats communicative. Thats useful now.
The winsock api is quite similar to Linux sockets in terms of function name and structures. Few differences exist like :
1. Winsock needs to be initialised with the WSAStartup function. No such thing in linux.
2. Header file names are different. Winsock needs winsock2.h , whereas Linux needs socket.h , apra/inet.h , unistd.h and many others.
3. Winsock function to close a socket is closesocket
, whereas on Linux it is close
.
On Winsock WSACleanup must also be called to unload the winsock dll.
4. On winsock the error number is fetched by the function WSAGetLastError()
. On Linux the errno variable from errno.h file is filled with the error number.
And there are many more differences as we go deep.
By now you must have learned the basics of socket programming in C. You can try out some experiments like writing a chat client or something similar.
If you think that the tutorial needs some addons or improvements or any of the code snippets above dont work then feel free to make a comment below so that it gets fixed.
Last Updated On : 12th December 2012 socket programmingwinsockwinsock tutorial
For this server to be any useful, it must be able to accept multiple incoming connections and keep processing them till the clients want. So the next attempt shall be to write a server that can handle multiple connections and tackle all of them simultaneously.
There are many ways to handle multiple client connections. The first and most intuitive one is using threads. As soon as a client connects, assign a separate thread to process each client. However threads are too much work and difficult to code properly.
There are other techniques like polling. Polling involves monitoring multiple sockets to see if "something" happened on any of them. For example, the server could be monitoring the sockets of 5 connected clients, and as soon as any of them send a message, the server gets notified of the event and then processes it. In this way it can handle multiple sockets. The winsock api provides a function called "select" which can monitor multiple sockets for some activity.
Since we are able to handle all sockets together at once it is called asynchronous socket programming. It is also called event-driven socket programming or select()-based multiplexing.
The select function prototype is like this
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout);
The first parameter is a dummy one. The readfds parameter is a pointer to an array of sockets which should be monitored to be readable. This means that if any socket in the readfds set receives some data, it becomes readable. Similarly the writefds sockets would be monitored to be writable and the exceptfds sockets shall be monitored for any error. The last parameter is the timeout parameter, which indicates the length of time which the select function shall wait for before returning.
Now after a select function returns, it re-fills the same readfds array with the readable sockets. Same with writefds and exceptfds. This means that we have to keep calling select function in a loop, and everytime have to prepare our list of readfds, writefds and exceptfds array of sockets to pass.
The socket arrays are variables of type fd_set. fd_set is basically a structure that looks like this
typedef struct fd_set { u_int fd_count; SOCKET fd_array[FD_SETSIZE]; } fd_set;
To work with fd_set array the following macros have to be used.
FD_CLR(s, *set) - Removes a socket from an fd_set structure FD_ISSET(s, *set) - Checks if a socket is present in an fd_set structure FD_SET(s, *set) - Adds a socket to an fd_set structure FD_ZERO(*set) - Initializes the set to the null set. This will empty an fd_set structure
Now that is a lot of theory. Lets get to the final code that uses all that theory to get something working.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187/*
TCP Echo server example in winsock
Live Server on port 8888
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib, "ws2_32.lib") //Winsock Library
int
main(
int
argc ,
char
*argv[])
{
WSADATA wsa;
SOCKET master , new_socket , client_socket[30] , s;
struct
sockaddr_in server, address;
int
max_clients = 30 , activity, addrlen, i, valread;
char
*message =
"ECHO Daemon v1.0 \r\n"
;
//size of our receive buffer, this is string length.
int
MAXRECV = 1024;
//set of socket descriptors
fd_set readfds;
//1 extra for null character, string termination
char
*buffer;
buffer = (
char
*)
malloc
((MAXRECV + 1) *
sizeof
(
char
));
for
(i = 0 ; i < 30;i++)
{
client_socket[i] = 0;
}
printf
(
"\nInitialising Winsock..."
);
if
(WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf
(
"Failed. Error Code : %d"
,WSAGetLastError());
exit
(EXIT_FAILURE);
}
printf
(
"Initialised.\n"
);
//Create a socket
if
((master = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf
(
"Could not create socket : %d"
, WSAGetLastError());
exit
(EXIT_FAILURE);
}
printf
(
"Socket created.\n"
);
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if
( bind(master ,(
struct
sockaddr *)&server ,
sizeof
(server)) == SOCKET_ERROR)
{
printf
(
"Bind failed with error code : %d"
, WSAGetLastError());
exit
(EXIT_FAILURE);
}
puts
(
"Bind done"
);
//Listen to incoming connections
listen(master , 3);
//Accept and incoming connection
puts
(
"Waiting for incoming connections..."
);
addrlen =
sizeof
(
struct
sockaddr_in);
while
(TRUE)
{
//clear the socket fd set
FD_ZERO(&readfds);
//add master socket to fd set
FD_SET(master, &readfds);
//add child sockets to fd set
for
( i = 0 ; i < max_clients ; i++)
{
s = client_socket[i];
if
(s > 0)
{
FD_SET( s , &readfds);
}
}
//wait for an activity on any of the sockets, timeout is NULL , so wait indefinitely
activity = select( 0 , &readfds , NULL , NULL , NULL);
if
( activity == SOCKET_ERROR )
{
printf
(
"select call failed with error code : %d"
, WSAGetLastError());
exit
(EXIT_FAILURE);
}
//If something happened on the master socket , then its an incoming connection
if
(FD_ISSET(master , &readfds))
{
if
((new_socket = accept(master , (
struct
sockaddr *)&address, (
int
*)&addrlen))<0)
{
perror
(
"accept"
);
exit
(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf
(
"New connection , socket fd is %d , ip is : %s , port : %d \n"
, new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//send new connection greeting message
if
( send(new_socket, message,
strlen
(message), 0) !=
strlen
(message) )
{
perror
(
"send failed"
);
}
puts
(
"Welcome message sent successfully"
);
//add new socket to array of sockets
for
(i = 0; i < max_clients; i++)
{
if
(client_socket[i] == 0)
{
client_socket[i] = new_socket;
printf
(
"Adding to list of sockets at index %d \n"
, i);
break
;
}
}
}
//else its some IO operation on some other socket :)
for
(i = 0; i < max_clients; i++)
{
s = client_socket[i];
//if client presend in read sockets
if
(FD_ISSET( s , &readfds))
{
//get details of the client
getpeername(s , (
struct
sockaddr*)&address , (
int
*)&addrlen);
//Check if it was for closing , and also read the incoming message
//recv does not place a null terminator at the end of the string (whilst printf %s assumes there is one).
valread = recv( s , buffer, MAXRECV, 0);
if
( valread == SOCKET_ERROR)
{
int
error_code = WSAGetLastError();
if
(error_code == WSAECONNRESET)
{
//Somebody disconnected , get his details and print
printf
(
"Host disconnected unexpectedly , ip %s , port %d \n"
, inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
closesocket( s );
client_socket[i] = 0;
}
else
{
printf
(
"recv failed with error code : %d"
, error_code);
}
}
if
( valread == 0)
{
//Somebody disconnected , get his details and print
printf
(
"Host disconnected , ip %s , port %d \n"
, inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
closesocket( s );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//add null character, if you want to use with printf/puts or other string handling functions
buffer[valread] =
'\0'
;
printf
(
"%s:%d - %s \n"
, inet_ntoa(address.sin_addr) , ntohs(address.sin_port), buffer);
send( s , buffer , valread , 0 );
}
}
}
}
closesocket(s);
WSACleanup();
return
0;
}
Does that look like a big program. Compile and run it. It should show an output like this
Initialising Winsock...Initialised. Socket created. Bind done Waiting for incoming connections...
Now the socket server is ready and waiting for incoming connection. At this point we need to connect to it using some client like telnet. But wait, we are not going to use telnet. Telnet has a problem that it always operates in character mode and that will screw up our interaction with this simple program. So get another utility called putty or ncat. Ncat is the netcat version that comes with nmap. Download it from their website. Or download puttytel , the putty telnet.
If you are using ncat then connect to the socket server like this
C:\>ncat localhost 8888
If you are using puttytel, the launch it and go to Connection > Telnet and select Passive mode. This will make putty line mode. Then come back to Session tab and enter the hostname and port and click open. it will connect to the server and start a black telnet like terminal.
Once the client program is connected with the server, try sending some message by typing first and then hit enter. The server will reply back with the same message.
C:\>ncat localhost 8888 ECHO Daemon v1.0 hello hello how are you how are you i am fine i am fine
The server terminal would look like this
Initialising Winsock...Initialised. Socket created. Bind done Waiting for incoming connections... New connection , socket fd is 3972 , ip is : 127.0.0.1 , port : 1129 Welcome message sent successfully Adding to list of sockets at index 0 127.0.0.1:1129 - hello 127.0.0.1:1129 - how are you 127.0.0.1:1129 - i am fine
And now, try to open multiple client terminals and connect at the same time to server. The server would be able to process requests from all the clients together.
Initialising Winsock...Initialised. Socket created. Bind done Waiting for incoming connections... New connection , socket fd is 3972 , ip is : 127.0.0.1 , port : 1129 Welcome message sent successfully Adding to list of sockets at index 0 127.0.0.1:1129 - hello 127.0.0.1:1129 - how are you 127.0.0.1:1129 - i am fine New connection , socket fd is 3956 , ip is : 127.0.0.1 , port : 1130 Welcome message sent successfully Adding to list of sockets at index 1 127.0.0.1:1130 - i am the second client New connection , socket fd is 3944 , ip is : 127.0.0.1 , port : 1131 Welcome message sent successfully Adding to list of sockets at index 2 127.0.0.1:1131 - and i am the third 127.0.0.1:1131 - ha ha ha
Now thats a long run. I will go and take a cup of coffee, and meanwhile you check if the programs are running fine.
Last Updated On : 28th March 2013 socket servertcpwinsock