socket学习
前几天学习了简单学习了一下socket编程,今天来回忆一下,自己在不借助资料的情况下写一下简单的C/S模式的socket。
socket是网络编程中很重要的一个部分,它相当于数据传输的一个端口。
客户端创建一个套接字socket的时候要指定相应的协议,本机的IP地址,本机的端口,这称为一个半相关。服务器端也是一样的,只有当两者用的协议相同,构成一个权相关,才能连接起来,进而通信。
服务器端:
1.初始化socket库
2.创建socket
3.设定地址
4.绑定socket
5.监听
6.建立通信
6.关闭socket
1 #include<iostream> 2 #include<winsock2.h> 3 #pragma comment(lib,"ws2_32.lib") 4 5 using namespace std; 6 7 int main() 8 { 9 //初始化socket 10 11 DWORD wVersion; 12 WSADATA w; 13 14 int err; 15 wVersion=MAKEWORD(1,1); 16 err=WSAStartup(wVersion,&w); 17 18 if(0==err) 19 { 20 cout<<"socket初始化成功!\n"; 21 } 22 else 23 { 24 cout<<"socket初始化失败!\n"; 25 } 26 27 if (LOBYTE(wVersion)!=1||HIBYTE(wVersion)!=1) 28 { 29 WSACleanup(); 30 return -1; 31 } 32 33 //创建socket 34 35 SOCKET sersock; 36 sersock=socket(AF_INET,SOCK_STREAM,0); 37 38 //设置地址 39 40 sockaddr_in seraddr; 41 seraddr.sin_family=AF_INET; 42 seraddr.sin_addr.S_un.S_addr=htonl(ADDR_ANY); 43 seraddr.sin_port=htons(6000); 44 45 //绑定 46 47 if(bind(sersock,(sockaddr *)&seraddr,sizeof(sockaddr))==SOCKET_ERROR) 48 { 49 cout<<"bind error!\n"; 50 WSACleanup(); 51 return-1; 52 } 53 54 //监听 55 56 listen(sersock,5); 57 //通信 58 59 SOCKET acsock; 60 sockaddr_in cliaddr; 61 int len=sizeof(sockaddr); 62 63 while(true) 64 { 65 acsock=accept(sersock,(sockaddr *)&cliaddr,&len); 66 if(acsock==INVALID_SOCKET) 67 { 68 cout<<"accept failed!\n"; 69 } 70 else 71 { 72 cout<<"accepted!\n"; 73 } 74 75 //发送消息 76 77 char buff[100]="I'm server!"; 78 int n=send(acsock,buff,sizeof(buff)+1,0); 79 if(n==0||n==SOCKET_ERROR) 80 { 81 cout<<"send failed!\n"; 82 } 83 else 84 { 85 cout<<"send finished!\n"; 86 } 87 88 Sleep(1000); 89 90 memset(buff,0,100); 91 92 int m=recv(acsock,buff,sizeof(buff)+1,0); 93 if(m==0||m==SOCKET_ERROR) 94 { 95 cout<<"receive failed!\n"; 96 } 97 else 98 { 99 cout<<"receive finished!\n"; 100 cout<<"message from "<<inet_ntoa(cliaddr.sin_addr)<<":"<<ntohs(cliaddr.sin_port)<<" "<<buff<<endl; 101 } 102 } 103 104 //关闭 105 if(closesocket(sersock)==SOCKET_ERROR) 106 { 107 cout<<"close error!\n"; 108 WSACleanup(); 109 } 110 WSACleanup(); 111 112 return 0; 113 }
客户端:
1.初始化socket
2.创建socket
3.设定地址
4.连接服务器
5.通信
6.关闭socket库
1 #include<iostream> 2 #include<winsock2.h> 3 #pragma comment(lib,"ws2_32.lib") 4 5 using namespace std; 6 7 int main() 8 { 9 //初始化socket 10 11 DWORD wVersion; 12 WSADATA ws; 13 14 wVersion=MAKEWORD(1,1); 15 16 int err=WSAStartup(wVersion,&ws); 17 18 if(err==0) 19 { 20 cout<<"初始化socket成功!\n"; 21 } 22 else 23 { 24 cout<<"初始化socket失败!\n"; 25 } 26 27 if(LOBYTE(wVersion)!=1||HIBYTE(wVersion)!=1) 28 { 29 cout<<"socket版本不对!\n"; 30 WSACleanup(); 31 } 32 33 //创建套接字 34 35 SOCKET clisock; 36 clisock=socket(AF_INET,SOCK_STREAM,0); 37 //设置地址 38 39 sockaddr_in cliaddr; 40 cliaddr.sin_family=AF_INET; 41 cliaddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.110"); 42 cliaddr.sin_port=htons(6000); 43 44 //连接服务器 45 46 if(connect(clisock,(sockaddr *)&cliaddr,sizeof(sockaddr))==SOCKET_ERROR) 47 { 48 cout<<"connect error!\n"; 49 WSACleanup(); 50 return -1; 51 } 52 else 53 { 54 cout<<"connected!\n"; 55 } 56 57 //通信 58 59 char buff[100]; 60 memset(buff,0,100); 61 62 if(recv(clisock,buff,sizeof(buff)+1,0)>0) 63 { 64 cout<<"receive message from server:"; 65 } 66 cout<<buff<<endl; 67 68 memset(buff,0,100); 69 cin.getline(buff,100); 70 71 if(send(clisock,buff,sizeof(buff)+1,0)>0) 72 { 73 cout<<"send ok!\n"; 74 } 75 //关闭 76 77 closesocket(clisock); 78 WSACleanup(); 79 return 0; 80 }
上述代码实现如下简单的功能:
先启动服务器端,等待客户端连接,客户端启动后,连接成功后,服务器发送消息,客户端收到消息后,输入消息,回应。
在学习过程中,需要注意如下几点:
1.在程序开头要加上#pragma comment(lib,"ws2_32.lib")告诉编译器有些东西要到ws2_32.lib库中去找
2.几个函数的使用不熟练:
inet_addr():将ip地址转化为S_addr结构类型
inet_ntoa():将S_addr结构类型转换成ip形式的字符串
htonl():将32位主机字节顺序转换成网络字节顺序
htons():将16位主机字节顺序转换成网络字节顺序
ntohl():与htonl()相反
ntohs(): 与htons()相反
3.程序在运行过程中,输出的端口不是6000,而是变化的,不知道为什么。。。
4.上面的程序是基于TCP协议的,TCP协议是面向连接的,以流的形式进行传输,而UDP协议不是面向连接的,以数据报的形式进行传输。TCP协议传输,数据的正确性和可靠性比UDP高。