服務器端的編寫:
1. 使用socket函數新建一個套接字,指定其 協議族family(AF_INET)、協議類型type(SOCK_STREAM)、協議(0, 系統根據family和type指定默認值)
2. 使用bind函數將本地協議地址綁定到套接字上,
3. 使用listen函數監聽客戶端發來的請求
4. 使用accept函數循環接受客戶端的請求
5. 使用send和recv函數發送和接收數據
客戶端程序的編寫 :
1. 使用socket函數創建一個套接字
2. 使用connect函數連接服務器
3. 使用send和recv發送和接受數據
示例如下:
由於使用winsock之前需要初始化winsock DLL,所以我將winsock的初始化和釋放封裝到了一個類中,如下:
1 // 初始化winsock
2
#include <winsock2.h>
3 #include <iostream>
4 class SockInitializer{
5 public:
6 SockInitializer()
7 {
8 WORD versionRequired = MAKEWORD( 2, 2);
9 WSADATA wsaData;
10 int ret = WSAStartup(versionRequired, &wsaData);
11 if ( 0 != ret){
12 std::cerr << " socket initialize failed ";
13 exit( 1);
14 }
15 }
16 ~SockInitializer(){
17 WSACleanup();
18 }
19 };
3 #include <iostream>
4 class SockInitializer{
5 public:
6 SockInitializer()
7 {
8 WORD versionRequired = MAKEWORD( 2, 2);
9 WSADATA wsaData;
10 int ret = WSAStartup(versionRequired, &wsaData);
11 if ( 0 != ret){
12 std::cerr << " socket initialize failed ";
13 exit( 1);
14 }
15 }
16 ~SockInitializer(){
17 WSACleanup();
18 }
19 };
接下來是服務器端的編寫:
注:關於listen的第二個參數backlog,我們可以為其指定一個環境變量,以隨時調整它的值
1
//
服務器端程序
2 #include <winsock2.h>
3 #include <cstdio>
4 #include <ctime>
5
6 using namespace std;
7
8 SockInitializer sockInitializer; // 初始化winsock
9
10 int main()
11 {
12 SOCKET listenfd, connfd;
13 sockaddr_in serverAddr;
14
15 char buf[ 100];
16 memset(buf, 0, sizeof(buf));
17
18 // 1. 建立一個socket
19 listenfd = socket(AF_INET, SOCK_STREAM, 0);
20 if (INVALID_SOCKET == listenfd){
21 cerr << " invalid socket ";
22 exit( 1);
23 }
24
25 // 2. 綁定到本地的端口
26 serverAddr.sin_family = AF_INET;
27 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用通配地址
28 serverAddr.sin_port = htons( 13); // 13是時間服務器的端口號
29
30 int ret = bind(listenfd, (sockaddr*)&serverAddr, sizeof(serverAddr) );
31 if (ret != 0){
32 cerr << " error on bind: " << WSAGetLastError();
33 exit( 1);
34 }
35
36 // 3. 開始監聽客戶端請求
37 listen(listenfd, SOMAXCONN); // listen的第二個參數指定了套接字排隊的最大連接個數,
38 // 我們為其指定 SOMAXCONN ,表示系統支持的最大連接個數
39 // 4. 循環接受客戶端的請求
40 while ( true){
41 cout << " accept ... " << endl;
42 connfd = accept(listenfd, (sockaddr*)NULL, NULL); // 這里我們不需要接受客戶端的sockaddr, 因此指定為NULL
43 if (INVALID_SOCKET == connfd){
44 cerr << " error on accept: " << WSAGetLastError() << endl;
45 continue;
46 }
47 cout << " successfully accept socket: " << connfd << endl;
48 time_t ticks = time(NULL);
49 snprintf(buf, sizeof(buf), " %.24s\r\n ", ctime(&ticks) );
50 send(connfd, buf, strlen(buf), 0 );
51
52 closesocket(connfd);
53 }
54 }
2 #include <winsock2.h>
3 #include <cstdio>
4 #include <ctime>
5
6 using namespace std;
7
8 SockInitializer sockInitializer; // 初始化winsock
9
10 int main()
11 {
12 SOCKET listenfd, connfd;
13 sockaddr_in serverAddr;
14
15 char buf[ 100];
16 memset(buf, 0, sizeof(buf));
17
18 // 1. 建立一個socket
19 listenfd = socket(AF_INET, SOCK_STREAM, 0);
20 if (INVALID_SOCKET == listenfd){
21 cerr << " invalid socket ";
22 exit( 1);
23 }
24
25 // 2. 綁定到本地的端口
26 serverAddr.sin_family = AF_INET;
27 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用通配地址
28 serverAddr.sin_port = htons( 13); // 13是時間服務器的端口號
29
30 int ret = bind(listenfd, (sockaddr*)&serverAddr, sizeof(serverAddr) );
31 if (ret != 0){
32 cerr << " error on bind: " << WSAGetLastError();
33 exit( 1);
34 }
35
36 // 3. 開始監聽客戶端請求
37 listen(listenfd, SOMAXCONN); // listen的第二個參數指定了套接字排隊的最大連接個數,
38 // 我們為其指定 SOMAXCONN ,表示系統支持的最大連接個數
39 // 4. 循環接受客戶端的請求
40 while ( true){
41 cout << " accept ... " << endl;
42 connfd = accept(listenfd, (sockaddr*)NULL, NULL); // 這里我們不需要接受客戶端的sockaddr, 因此指定為NULL
43 if (INVALID_SOCKET == connfd){
44 cerr << " error on accept: " << WSAGetLastError() << endl;
45 continue;
46 }
47 cout << " successfully accept socket: " << connfd << endl;
48 time_t ticks = time(NULL);
49 snprintf(buf, sizeof(buf), " %.24s\r\n ", ctime(&ticks) );
50 send(connfd, buf, strlen(buf), 0 );
51
52 closesocket(connfd);
53 }
54 }
客戶端程序:
1 // 客戶端程序
2
#include <winsock2.h>
3 #include <cstdio>
4 #include <iostream>
5
6 using namespace std;
7
8 SockInitializer sockInitializer; // 初始化winsock
9
10 int main( int argc, char **argv)
11 {
12 if (argc != 2){
13 cerr << " usage: client <ipaddress> ";
14 exit( 1);
15 }
16
17 // 1. 創建套接字
18 SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
19 if (sockfd == INVALID_SOCKET){
20 cerr << " invalid socket ";
21 exit( 1);
22 }
23
24 // 2. 連接至服務器
25 sockaddr_in serverAddr;
26 memset(&serverAddr, 0, sizeof serverAddr);
27 serverAddr.sin_family = AF_INET;
28 serverAddr.sin_port = htons( 13);
29 serverAddr.sin_addr.s_addr = inet_addr(argv[ 1]);
30
31 int ret = connect(sockfd, (SOCKADDR*)&serverAddr, sizeof serverAddr); // 指定服務器的地址
32 if ( 0 != ret){
33 cout << " error on connect: " << WSAGetLastError();
34 exit( 1);
35 }
36
37 // 3. 接受數據
38 char buf[ 100];
39 int n;
40 while ( 0 != (n = recv(sockfd, buf, sizeof buf, 0) ) ){
41 buf[n] = ' \0 ';
42 cout << buf;
43 }
44 }
3 #include <cstdio>
4 #include <iostream>
5
6 using namespace std;
7
8 SockInitializer sockInitializer; // 初始化winsock
9
10 int main( int argc, char **argv)
11 {
12 if (argc != 2){
13 cerr << " usage: client <ipaddress> ";
14 exit( 1);
15 }
16
17 // 1. 創建套接字
18 SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
19 if (sockfd == INVALID_SOCKET){
20 cerr << " invalid socket ";
21 exit( 1);
22 }
23
24 // 2. 連接至服務器
25 sockaddr_in serverAddr;
26 memset(&serverAddr, 0, sizeof serverAddr);
27 serverAddr.sin_family = AF_INET;
28 serverAddr.sin_port = htons( 13);
29 serverAddr.sin_addr.s_addr = inet_addr(argv[ 1]);
30
31 int ret = connect(sockfd, (SOCKADDR*)&serverAddr, sizeof serverAddr); // 指定服務器的地址
32 if ( 0 != ret){
33 cout << " error on connect: " << WSAGetLastError();
34 exit( 1);
35 }
36
37 // 3. 接受數據
38 char buf[ 100];
39 int n;
40 while ( 0 != (n = recv(sockfd, buf, sizeof buf, 0) ) ){
41 buf[n] = ' \0 ';
42 cout << buf;
43 }
44 }
