基本的TCP socket编程示例 -- 时间服务器及客户端
服务器端的编写:
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 }