三,
Socket编程实例
讲了这么多其实还是看实例最为重要了,下面我提供了最简单的面向连接的客户端和服务端程序,
当服务端接受客户端的连接后,先是该客户机地IP地址,并向客户端发送一个回应消息,
最后关闭该连接套接字。这样的服务器当然没什么实际的用途。
设计一个基本的网络服务器有以下几个步骤:
1、初始化Windows Socket
2、创建一个监听的Socket
3、设置服务器地址信息,并将监听端口绑定到这个地址上
4、开始监听
5、接受客户端连接
6、和客户端通信
7、结束服务并清理Windows Socket和相关数据,或者返回第4步
#include <winsock2.h>
#include <stdio.h>
#define SERVPORT
5050
#pragma comment(lib,"ws2_32.lib")
void main(void)
{
WSADATA wsaData;
SOCKET sListen; //
监听socket
SOCKET sClient;
// 连接socket
SOCKADDR_IN serverAddr; //
本机地址信息
SOCKADDR_IN clientAddr; //
客户端地址信息
int clientAddrLen;
// 地址结构的长度
int nResult;
// 初始化Windows Socket 2.2
WSAStartup(MAKEWORD(2,2), &wsaData);
// 创建一个新的Socket来响应客户端的连接请求
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 填写服务器绑定的地址信息
// 端口为5150
// IP地址为INADDR_ANY,响应每个网络接口的客户机活动
// 注意使用htonl将IP地址转换为网络格式
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVPORT);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(serverAddr.sin_zero), 0, sizeof(serverAddr.sin_zero));
// 绑定监听端口
nResult = bind(sListen, (SOCKADDR *)&serverAddr, sizeof(SOCKADDR));
if (nResult == SOCKET_ERROR)
{
printf("bind failed!\n");
return;
}
// 开始监听,指定最大接受队列长度5,不是连接数的上限
listen(sListen, 5);
// 接受新的连接
while(1)
{
clientAddrLen = sizeof (SOCKADDR);
sClient = accept(sListen, (SOCKADDR *)&clientAddr, &clientAddrLen);
if(sClient == INVALID_SOCKET)
{
printf("Accept failed!");
}
else
{
printf("Accepted client: %s : %d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
// 向客户端发送信息
nResult = send(sClient, "Connect success!", 16, 0);
if (nResult == SOCKET_ERROR)
{
printf("send failed!");
}
}
// 我们直接关闭连接,
closesocket(sClient);
}
// 并关闭监听Socket,然后退出应用程序
closesocket(sListen);
// 释放Windows Socket DLL的相关资源
WSACleanup();
}
客户机程序如下:
#include <winsock2.h>
#include <stdio.h>
#define SERVPORT
5050 // 端口为5150
#define MAXDATASIZE 100
#define SERVIP
"127.0.0.1" // 服务器IP地址为"127.0.0.1",注意使用inet_addr将IP地址转换为网络格式
#pragma comment(lib,"ws2_32.lib")
void main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET sConnect;
SOCKADDR_IN serverAddr;
int recvbytes;
char buf[MAXDATASIZE];
//初始化Windows Socket 2.2
WSAStartup(MAKEWORD(2,2), &wsaData);
// 创建一个新的Socket来连接服务器
sConnect = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 填写连接地址信息
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVPORT);
serverAddr.sin_addr.s_addr = inet_addr(SERVIP);
memset(&(serverAddr.sin_zero), 0, sizeof(serverAddr.sin_zero));
// 向服务器发出连接请求
if (connect(sConnect, (SOCKADDR *)&serverAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
printf("connect failed!\n");
return;
}
// 接受服务器的回应消息
recvbytes = recv(sConnect, buf, MAXDATASIZE, 0);
if (recvbytes == SOCKET_ERROR)
{
printf("recv failed!\n");
}
else
{
buf[recvbytes] = '\0';
printf("%s\n",buf);
}
closesocket(sConnect);
// 释放Windows Socket DLL的相关资源
WSACleanup();
}
四,
结束语
这里介绍的只不过是winsock最基础最基础的知识,开发网络程序从来都不是一件容易的事情,
尽管只需要遵守很少的一些规则:
创建套接字,发起连接,接受连接,
发送和接受数据。真正的困难在于:让你的程序可以适应从单单一个连接到几千个连接,
即开发一个大容量,具可扩展性的Winsock应用程序。
Winscok编程很重要的一部分是IO处理,分别提供了“套接字模式”和“套接字I/O模型”,
可对一个套接字上的I/O行为进行控制。
其中,套接字模式用于决定在随一个套接字调用时,那些Winsock函数的行为,
有阻塞和非阻塞两种模式。
而另一方面,套接字模型描述了一个应用程序如何对套接字上进行的I/O进行管理及处理,
包括包括Select,WSAAsyncSelect,WSAEventSelect
,IO重叠模型,完成端口等。
在这里推荐一本好书《windows网络编程技术》,有兴趣研究的同志可以去啃一啃