协议图文详解
流式套接字(TCP)
数据报套接字
代码实例通信:
服务器端代码:
1 // socketserver.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include "conio.h"
6 #include "windows.h"
7 //socket头文件
8 #include "winsock.h"
9 //socket库的lib
10 #pragma comment(lib,"ws2_32.lib")
11
12 void TCPServer()
13 {
14 /***************创建服务器端套接字SOCKET*******************/
15 /*******socket()函数解释:IP协议族,数据流方式,TCP协议****/
16 SOCKET socksvr=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
17 if(INVALID_SOCKET == socksvr)
18 {
19 return;
20 }
21 /*************建立服务器端套接字地址***********************/
22 /********************绑定IP和端口号******************/
23 struct sockaddr_in svraddr = {0};
24 svraddr.sin_family = AF_INET;//代表internet协议族
25 /**htons()函数解释:是将u_short型变量从主机字节顺序变换为TCP/IP网络字节顺序**/
26 /**这里涉及大小端系统问题。intel处理器是低位字节在****************/
27 /**较低地址存放,而高位字节在较高地址存放,与网络字节顺序相反,故需要调换过来****/
28 svraddr.sin_port = htons(5678);
29 //htonl()函数是将u_long型变量从主机字节顺序变为TCP/IP网络字节顺序。
30 svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//此宏为0,当前机器上任意IP地址,也可以指定当前机的ip和端口。
31 //绑定,将服务器端套接字与服务器端套接字地址绑定
32 bind(socksvr,(struct sockaddr *)&svraddr,sizeof(svraddr));//指定名字,类型,长度。绑定套接字。
33 //侦听
34 listen(socksvr,SOMAXCONN);//第一个参数是套接字,第二个参数是等待连接队列的最大长度。
35 //等候客户端建立连接
36 printf("等候客户端.......\n");
37 //建立客户端套接字地址,主要是为了接收客户端返回参数之用
38 struct sockaddr_in clientaddr = {0};
39 int nLen = sizeof(clientaddr);
40 //以下是建立客户端套接字并建立连接函数。有一个确认的过程。
41 //注:后面填的是客户端地址长度的地址。
42 SOCKET sockclient = accept(socksvr,(struct sockaddr*)&clientaddr,&nLen);//建立连接函数
43 printf("客户端已连接\n");
44 /********以下是数据收发部分*********/
45 //先接收后发送,由上面知,数据已在sockclient中,我们只需读此结构便可知晓数据
46 CHAR szText[100] = {0};
47 //接收缓冲区数据
48 recv(sockclient,szText,100,0); //接收函数,一直处于侦听模式,等待服务器端发送数据的到来。
49 printf("%s\n",szText);
50 CHAR szSend[100] = "Hello Client";
51 send(sockclient,szSend,sizeof(szSend),0);//发送函数。
52 /****accept/recv/send 都是堵塞函数,需要把所以的数据都接收完或发送完才可以工作。*****/
53 // getch();//暂停一下
54 //关闭socket
55 closesocket(sockclient);
56 closesocket(socksvr);
57
58
59 }
60
61 void UDPServer()
62 {
63 //创建socket
64 SOCKET socksvr = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
65 if(INVALID_SOCKET == socksvr)
66 {
67 return ;
68 }
69 //服务器套接字地址
70 //绑定ip与端口,先定义端口等一些信息。
71 struct sockaddr_in svraddr = {0};
72 svraddr.sin_family = AF_INET;
73 svraddr.sin_port = htons(5780);
74 svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
75 bind(socksvr,(struct sockaddr*)&svraddr,sizeof(svraddr));
76
77 /********以下是数据收发部分*********/
78 //客户端套接字地址,接收客户端数据时需要用,数据都在套接字里面。
79 CHAR szRecv[100] = {0};
80 struct sockaddr_in clientaddr = {0};
81 int nLen = sizeof(clientaddr);
82 /*下面函数前四个参数同TCP接收数据函数recv()一样,后两个中,一个是返回发送*******/
83 /*数据地址的主机的地址,包括IP地址以及端口号,最后一个为地址长度的地址。*******/
84 /*此函数中,先是服务器端的套接字,后是客户端的地址*/
85 //从后往前读此函数
86 recvfrom(socksvr,szRecv,100,0,(struct sockaddr*)&clientaddr,&nLen);//构造ip地址
87 printf("%s\n",szRecv);
88
89 //注1:该程序也可以向客户端发送数据。
90 //注2:服务器端中,必须也是先接收后发送,不然,我们无法知道客户端的地址。下面函数中clientaddr已知晓
91 CHAR szSend[100] = "hello udp client";
92 //从前往后读此函数
93 sendto(socksvr,szSend,100,0,(struct sockaddr*)&clientaddr,nLen);//发送时构造ip地址和端口。
94
95 // getch();//可以暂停显示,这个很重要。
96
97 //关闭socket
98 closesocket(socksvr);
99
100
101 }
102
103
104
105
106
107 int main(int argc, _TCHAR* argv[])
108 {
109 //初始化socket库
110 WSADATA wsa = {0}; //WinSockApi 取WSA+DATA组成套接字结构体
111 WSAStartup(MAKEWORD(2,2),&wsa);
112 //服务器
113 TCPServer();
114 //UDPServer();
115 //清理套接字资源
116 WSACleanup();
117 getch();//暂停一下
118
119 return 0;
120 }
客户端代码:
1 // socketclint.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include "conio.h"
6 #include "windows.h"
7 #include "winsock.h"
8 #pragma comment(lib,"ws2_32.lib")
9
10 void TCPClient()
11 {
12 //创建socket
13 SOCKET sockclient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
14 if(INVALID_SOCKET == sockclient)
15 {
16 return;
17 }
18 //连接服务器,建立服务器端套接字地址
19 struct sockaddr_in addr = {0};
20 addr.sin_family = AF_INET;
21 addr.sin_port = htons(5678);
22 //对于inet_addr()函数,它是把“xxx.xxx.xxx.xxx”形式表示的IPV4地址,转换为IN_ADDR结构体能够
23 //接收的形式(unsigned long型,因为IN_ADDR结构体中的负责接收的S_addr成员变量的类型是unsigned long型)
24 addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//本机ip
25
26 //向服务器发出连接请求,当然我们也可以通过connet函数的返回值判断到底有无连接成功。
27 int iRetVal = connect(sockclient,(struct sockaddr*)&addr,sizeof(addr));
28 if(SOCKET_ERROR == iRetVal)
29 {
30 printf("服务器连接失败!");
31 closesocket(sockclient);
32 return;
33 }
34 printf("服务器连接成功!\n");
35 //数据收发
36 CHAR szSend[100] = "hello server"; //客户端 先发后收
37 send(sockclient,szSend,sizeof(szSend),0); //发送函数,可以通过返回值判断发送成功与否。
38
39 //接收服务器回传的数据
40 CHAR szRecv[100] = {0};
41 recv(sockclient,szRecv,100,0); //接收函数
42 printf("%s\n",szRecv);//表示以字符串的格式输出服务器端发送的内容。
43
44 // getch();//暂停一下
45 //关闭socket
46 closesocket(sockclient);
47 }
48 void UDPClient()
49 {
50 //创建SOCKET ,ip协议族,数据报方式,udp协议。
51 SOCKET sockclient = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
52 if(INVALID_SOCKET == sockclient)
53 {
54 return ;
55 }
56 //数据收发,服务器端套接字地址
57 struct sockaddr_in svraddr = {0};
58 svraddr.sin_family = AF_INET;
59 svraddr.sin_port = htons(5780);
60 svraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//指定服务器端的IP与端口。
61 CHAR szSend[100] = "hello udp server";
62 /*此函数先是客户端的套接字,然后是服务器端地址*/
63 //简单理解为:从函数前面的客户端套接字的发送数据缓存区中将数发送给服务器端地址
64 sendto(sockclient,szSend,100,0,(struct sockaddr*)&svraddr,sizeof(svraddr));//发送时构造ip地址和端口。
65
66 //注:该程序也可以接收服务器端回传的数据。
67 CHAR szRecv[100];
68 //简单理解为:从函数后面的服务器端地址中取数到客户端套接字的接收缓冲区szRecv中
69 int len = sizeof(svraddr);
70 recvfrom(sockclient,szRecv,100,0,(struct sockaddr*)&svraddr,&len);
71 printf("%s \n",szRecv);
72 //关闭socket
73 closesocket(sockclient);
74 }
75
76 int main(int argc, _TCHAR* argv[])
77 {
78 //初始化socket库
79 WSADATA wsa = {0};
80 WSAStartup(MAKEWORD(2,2),&wsa);
81 //tcp客户端
82 TCPClient();
83 //UDPClient();
84 //清理套接字资源
85 WSACleanup();
86 getch();
87
88
89 return 0;
90 }