一、基于TCP的socket编程
服务器端程序:
1)创建套接字(socket)。
此系统调用的实际效果是,请求操作系统把网络通信所需要的一些系统资源(存储器空间、CPU时间、网络宽带等)分配给该应用进程。
2)将套接字绑定到一个本地地址和端口上(bind)。
3)将套接字设为监听模式,准备接收客户请求(listen)。
4)等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。
5)用返回的套接字和客户端进行通信(send/recv)。
6)返回,等待另一客户请求。
7)关闭套接字(closesocket)。
此系统调用,通知操作系统回收与该套接字描述符相关的所有资源。
客户端程序:
1)创建套接字(socket)。
2)向服务器发出连接请求(connect)。
3)和服务器端进行通信(send/recv)。
4)关闭套接字(closesocket)。
二、基于UDP的socket编程
服务器端(接收端)程序:
1)创建套接字(socket)。
2)将套接字绑定到一个本地地址和端口上(bind)。
3)等待接收数据(recvfrom)。
4)关闭套接字(closesocket)。
客户端(发送端)程序:
1)创建套接字(socket)。
2)向服务器发送数据(sendto)。
3)关闭套接字(closesocket)。
三、相关函数
1)int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); //启动进程使用ws2.dll
wVersionRequested参数:用于指定准备加载的Winsock库的版本。高位字节指定所需要的Winsock库的副版本,而低位字节则是主版本。可用MAKEWORD(x, y);(其中,x是高位字节,y是低位字节)方便地获得wVersionRequested的正确值。
lpWSAData参数:指向WSADATA结构的指针,WSAStartup用其加载的库版本有关的信息填在这个结构中。
2)SOCKET socket(int af, int type, int protocol); //创建与特定服务提供者绑定的套接字
af参数:指定地址族,对于TCP/IP协议的套接字,它只能是AF_INET(也可写成PF_INET)。
type参数:指定Socket类型,对于1.1版本的Socket,它只支持两种类型的套接字,SOCK_STREAM指定产生流式套接字,SOCK_DGRAM产生数据报套接字。
protocol参数:与特定的地址家族相关的协议,如果指定为0,那么它就会根据地址格式和套接字类别,自动为你选择一个合适的协议。这是推荐使用的一种选择协议的方法。
3)int bind(SOCKET s, const struct sockaddr FAR *name, int namelen); //将套接字和本地地址联系起来
s参数:指定要绑定的套接字。
name参数:指定了该套接字的本地地址信息。
namelen参数:指定name所指向的sockaddr结构的长度。
四、实例
(1)基于TCP的Socket编程
服务器端,创建一个Win32的控制台应用程序,新建一个cpp文件,取名为Server.cpp,其代码如下:
- #pragma comment(lib,"Ws2_32.lib")
- #include <Winsock2.h>
- #include <iostream>
- using namespace std;
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- //********获取应用程序所需的Winsock DLL版本信息
- WORD wVersionRequested;
- wVersionRequested = MAKEWORD(1, 1); //设置高字节为1,低字节为1的WORD类型,表示所需Windows Sockets的版本号为1.1
- WSADATA wsaData; //用来存储获取的Windows Sockets的信息
- int err = WSAStartup(wVersionRequested, &wsaData); //初始化此进程的Winsock DLL的使用
- //初始化失败,直接返回
- if (err != 0)
- {
- return 1;
- }
- //告诉使用者,找不到可用的Winsock DLL
- if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
- {
- WSACleanup();
- return 1;
- }
- //*********创建套接字
- SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);
- //*********将套接字绑定到一个本地地址和端口上
- sockaddr_in addrServer; //存储sock地址信息
- addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //IP地址为INADDR_ANY,允许套接字向任何分配给本地机器的IP地址发送或接收数据
- addrServer.sin_family = AF_INET; //地址簇
- addrServer.sin_port = htons(6000);
- bind(sockServer, (sockaddr *)&addrServer, sizeof(sockaddr));
- //*********将套接字设为监听模式,准备接收客户请求
- listen(sockServer, 5); //监听的套接字最大数为5
- //*********等待客户请求到来
- sockaddr_in addrClient; //存储sock所连接的客户端的地址信息
- int addrlen = sizeof(sockaddr);
- while (1)
- {
- //当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字
- SOCKET sockConnect = accept(sockServer, (sockaddr *)&addrClient, &addrlen);
- //*********用返回的套接字和客户端进行通信
- char pBuffer[100];
- memset(pBuffer, 0, 100);
- strcat(pBuffer, "Welcome ");
- strcat(pBuffer, inet_ntoa(addrClient.sin_addr));
- strcat(pBuffer, " to http://www.sunxin.org!");
- send(sockConnect, pBuffer, (strlen(pBuffer) + 1) * sizeof(char), 0); //给客户端发送消息
- char recvBuf[100];
- memset(recvBuf, 0, 100);
- recv(sockConnect, recvBuf, 100, 0); //接收客户端发来的消息
- //*********关闭socket连接
- closesocket(sockConnect);
- cout<<recvBuf<<endl;
- }
- return 0;
- }
客户端,创建一个Win32的控制台应用程序,新建一个cpp文件,取名为Client.cpp,其代码如下:
- #pragma comment(lib,"Ws2_32.lib")
- #include <Winsock2.h>
- #include <iostream>
- using namespace std;
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- //********获取应用程序所需的Winsock DLL版本信息
- WORD wVersionRequested;
- wVersionRequested = MAKEWORD(1, 1); //设置高字节为1,低字节为1的WORD类型,表示所需Windows Sockets的版本号为1.1
- WSADATA wsaData; //用来存储获取的Windows Sockets的信息
- int err = WSAStartup(wVersionRequested, &wsaData); //初始化此进程的Winsock DLL的使用
- //初始化失败,直接返回
- if (err != 0)
- {
- return 1;
- }
- //告诉使用者,找不到可用的Winsock DLL
- if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
- {
- WSACleanup();
- return 1;
- }
- //*********创建套接字
- SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
- //*********向服务器发出连接请求
- sockaddr_in addrServer; //存储服务器端的sock地址信息
- addrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //服务器IP地址,此处服务器为本机
- addrServer.sin_family = AF_INET; //地址簇
- addrServer.sin_port = htons(6000);
- connect(sockClient, (sockaddr *)&addrServer, sizeof(sockaddr));
- //*********和服务器端进行通信
- char *pBuffer = "This is liuxijiao.";
- send(sockClient, pBuffer, (strlen(pBuffer) + 1) * sizeof(char), 0); //给服务器发送消息
- char recvBuf[100];
- memset(recvBuf, 0, 100);
- recv(sockClient, recvBuf, 100, 0); //接收服务器发来的消息
- //*********关闭socket连接
- closesocket(sockClient);
- WSACleanup();
- cout<<recvBuf<<endl;
- system("PAUSE");
- return 0;
- }
首先运行服务器端的程序,然后再运行客户端的程序。
在服务器端收到客户端发送来的消息:
在客户端收到服务器端发送来的消息:
(2)基于UDP的Socket编程
服务器端,创建一个Win32的控制台应用程序,新建一个cpp文件,取名为Server.cpp,其代码如下:
- #pragma comment(lib, "Ws2_32.lib")
- #include <Winsock2.h>
- #include <iostream>
- using namespace std;
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- //********获取应用程序所需的Winsock DLL版本信息
- WORD wVersionRequested;
- wVersionRequested = MAKEWORD(1, 1); //设置高字节为1,低字节为1的WORD类型,表示所需Windows Sockets的版本号为1.1
- WSADATA wsaData; //用来存储获取的Windows Sockets的信息
- int err = WSAStartup(wVersionRequested, &wsaData); //初始化此进程的Winsock DLL的使用
- //初始化失败,直接返回
- if (err != 0)
- {
- return 1;
- }
- //告诉使用者,找不到可用的Winsock DLL
- if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
- {
- WSACleanup();
- return 1;
- }
- //***********创建套接字
- SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, 0);
- //***********将套接字绑定到一个本地地址和端口上
- sockaddr_in addrServer;
- addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
- addrServer.sin_family = AF_INET;
- addrServer.sin_port = htons(6000);
- bind(sockServer, (sockaddr *)&addrServer, sizeof(sockaddr));
- //***********等待接收数据
- char pBuffer[100];
- memset(pBuffer, 0, 100);
- sockaddr_in addrClient;
- int len = sizeof(sockaddr_in);
- recvfrom(sockServer, pBuffer, 100, 0, (sockaddr *)&addrClient, &len); //接受客户端发来的消息
- //***********关闭套接字
- closesocket(sockServer);
- cout<<pBuffer<<endl;
- system("PAUSE");
- return 0;
- }
客户端,创建一个Win32的控制台应用程序,新建一个cpp文件,取名为Client.cpp,其代码如下:
- #pragma comment(lib, "Ws2_32.lib")
- #include <Winsock2.h>
- #include <iostream>
- using namespace std;
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- //********获取应用程序所需的Winsock DLL版本信息
- WORD wVersionRequested;
- wVersionRequested = MAKEWORD(1, 1); //设置高字节为1,低字节为1的WORD类型,表示所需Windows Sockets的版本号为1.1
- WSADATA wsaData; //用来存储获取的Windows Sockets的信息
- int err = WSAStartup(wVersionRequested, &wsaData); //初始化此进程的Winsock DLL的使用
- //初始化失败,直接返回
- if (err != 0)
- {
- return 1;
- }
- //告诉使用者,找不到可用的Winsock DLL
- if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
- {
- WSACleanup();
- return 1;
- }
- //***********创建套接字
- SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);
- //***********向服务器发送数据
- char *pBuffer = "Hello, server!";
- sockaddr_in addServer;
- addServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
- addServer.sin_family = AF_INET;
- addServer.sin_port = htons(6000);
- sendto(sockClient, pBuffer, (strlen(pBuffer) + 1) * sizeof(char), 0, (sockaddr *)&addServer, sizeof(sockaddr_in));
- //***********关闭套接字
- closesocket(sockClient);
- return 0;
- }
-
首先运行服务器端的程序,然后再运行客户端的程序。可看见在服务器端收到客户端发送来的消息: