-----初更----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 }