Loading

【C++】socket编程(二):最简单的socket通信(下)

-----初更----2018年1月29日(转载请注明出处)----

前言:

有很多人看完上一节后,一头雾水,我是谁?我在哪?我在干什么?其实socket问题就类似于把大象放进冰箱总共分几步的问题,这时候就要咬咬牙,把这两章需要用得到的函数搞明白,以后就是这些函数的伸展了

#0x01    accept()函数

accept()是服务端的函数。从上一张开始说,服务端bind之后,做好listen的准备,这时候,客户端说:喂,我要连接(connent),服务器端就要回话:喂,我知道了(accept),这就是accept的意思,当然实际使用accept函数可是非常强大呢!

我们先看一下使用方法

Linux/windows

1     SOCKADDR clntAddr;//客户端信息
2     int nSize = sizeof(SOCKADDR);//字节大小
3     SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);

可以看到,accept函数和bind()函数很像,在使用之前,需要再建立一个socket结构体,为什么呢?因为服务端作为接受嘛,可能有不同的人在叫他,他不知道谁在叫他,所以在有人叫他时候,就要拿个小本本记下来,知道张三叫了他,地址是*¥@*&¥*#,然后服务器在向这个地址回话:Hello World!这就是accept函数的作用。

#0x02    发送函数

Windows:

在windows下呢,发送嘛,不就是send嘛,没错,发送函数就是send(),只是具体用法是:

send(clntSock, str, strlen(str) + sizeof(char), NULL);

 

函数原型是

int send(
  _In_       SOCKET s,//最开始创建的套接字
  _In_ const char   *buf,//需发送的字符串
  _In_       int    len,//发送字符串的长度
  _In_       int    flags//标志位
);

 

 看完原型应该就知道怎么使用了,比较简单,还有,别问我标志位是什么用,我还不知道,尴尬,只是官方解释可以忽略。

 Linux:

linux下的原型和windows差不多,只不过没有了官方说可以忽略的选项,名字换了一下而已。

write(clnt_sock, str, sizeof(str));

 

 write有点意思,好像在哪见过,没错,这就是写入文件函数,因为在linux的思想就是一切皆文件,所以socket通信也被看做是往socket管道中写入字符,所以就有了write。

#0x03    接收函数

Windows:

windows下接收函数和发送函数参数一样,只是函数名表不一样

recv(sock, szBuffer, MAXBYTE, NULL);

 

 Linux:

Linux下也是和发送函数相反

read(sock, buffer, sizeof(buffer)-1);

 

0x04    关闭通道

Windows:

Windows下直接调用函数就可以关闭套接字

closesocket(sock);

 

sock还是最开始创建的套接字

Linux:

Linux下也是一样,只是函数不一样

close(sock);

 

0x05    图解

怎么样,现在需要用到的函数都讲完了,是不是懵逼了,其实只要弄明白每个函数是做什么的就可以了,废话不多说,直接放图

有没有大彻大悟!!!这张图很好的解释了socket的工作原理,一定要把这张图吃透!!!

0x06    代码

说了一堆堆理论,是时候亮出真家伙了!!!代码才是最锋利的武器对不对,不多说直接上代码(注:一定要把前面的每个函数都弄懂在看代码,然后自己尝试写出来!)

Windows:

 1 #include <stdio.h>
 2 #include <winsock2.h>
 3 #pragma comment (lib, "ws2_32.lib")  //加载 ws2_32.dll
 4 
 5 /*服务器端代码*/
 6 
 7 int main(){
 8     //初始化 DLL
 9     WSADATA wsaData;
10     WSAStartup( MAKEWORD(2, 2), &wsaData);
11 
12     //创建套接字
13     SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
14 
15     //绑定套接字
16     sockaddr_in sockAddr;
17     memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
18     sockAddr.sin_family = PF_INET;  //使用IPv4地址
19     sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
20     sockAddr.sin_port = htons(1555);  //端口
21     bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
22 
23     //进入监听状态
24     listen(servSock, 20);
25 
26     //接收客户端请求
27     SOCKADDR clntAddr;
28     int nSize = sizeof(SOCKADDR);
29     SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);
30 
31     //向客户端发送数据
32     char *str = "Hello World!";
33     send(clntSock, str, strlen(str)+sizeof(char), NULL);
34 
35     //关闭套接字
36     closesocket(clntSock);
37     closesocket(servSock);
38 
39     //终止 DLL 的使用
40     WSACleanup();
41 
42     return 0;
43 }
Windows服务器端代码

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <WinSock2.h>
 4 #pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
 5 
 6 /*客户端代码*/
 7 
 8 int main(){
 9     //初始化DLL
10     WSADATA wsaData;
11     WSAStartup(MAKEWORD(2, 2), &wsaData);
12 
13     //创建套接字
14     SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
15 
16     //向服务器发起请求
17     sockaddr_in sockAddr;
18     memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
19     sockAddr.sin_family = PF_INET;
20     sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
21     sockAddr.sin_port = htons(1555);
22     connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
23 
24     //接收服务器传回的数据
25     char szBuffer[MAXBYTE] = {0};
26     recv(sock, szBuffer, MAXBYTE, NULL);
27 
28     //输出接收到的数据
29     printf("Message form server: %s\n", szBuffer);
30 
31     //关闭套接字
32     closesocket(sock);
33 
34     //终止使用 DLL
35     WSACleanup();
36 
37     system("pause");
38     return 0;
39 }
Windows客户端代码

 

Linux:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 #include <netinet/in.h>
 8 
 9 /*服务器端代码*/
10 
11 int main(){
12     //创建套接字
13     int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
14 
15     //将套接字和IP、端口绑定
16     struct sockaddr_in serv_addr;
17     memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
18     serv_addr.sin_family = AF_INET;  //使用IPv4地址
19     serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
20     serv_addr.sin_port = htons(1555);  //端口
21     bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
22 
23     //进入监听状态,等待用户发起请求
24     listen(serv_sock, 20);
25 
26     //接收客户端请求
27     struct sockaddr_in clnt_addr;
28     socklen_t clnt_addr_size = sizeof(clnt_addr);
29     int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
30 
31     //向客户端发送数据
32     char str[] = "Hello World!";
33     write(clnt_sock, str, sizeof(str));
34    
35     //关闭套接字
36     close(clnt_sock);
37     close(serv_sock);
38 
39     return 0;
40 }
Linux服务器端代码
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 /*客户端代码*/
 9 
10 int main(){
11     //创建套接字
12     int sock = socket(AF_INET, SOCK_STREAM, 0);
13 
14     //向服务器(特定的IP和端口)发起请求
15     struct sockaddr_in serv_addr;
16     memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
17     serv_addr.sin_family = AF_INET;  //使用IPv4地址
18     serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
19     serv_addr.sin_port = htons(1555);  //端口
20     connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
21    
22     //读取服务器传回的数据
23     char buffer[40];
24     read(sock, buffer, sizeof(buffer)-1);
25    
26     printf("Message form server: %s\n", buffer);
27    
28     //关闭套接字
29     close(sock);
30 
31     return 0;
32 }
Linux客户端代码

 

0x07    参考

【1】特别参考:http://c.biancheng.net/cpp/html/3031.html

【2】特别参考:http://c.biancheng.net/cpp/html/3030.html

 

posted @ 2018-01-29 20:58  _小孟同学  阅读(3669)  评论(0编辑  收藏  举报