如何学习网络编程,学习网络编程要确定你要做什么样的程序,如果是普通的应用程序的网络编程,你可能对网络内部原理不理解也没有多大问题,直接学会网络编程的各种接口,但如果你是要做高性能服务端程序或者是嵌入式设备的程序,那就要求你对网络编程原理有一定理解,因为你需要解决很多复杂的问题,只看api接口是不够的。
网络编程我们涉及到的第一个案例概念的就是socket或者套接字,这个名字就起的让人不容易理解,其实IT的很多概念的名字起得都让人不容易理解,这估计也和我们IT人员高智商有关。
我试着用最简单的话解释一下Socket,"socket接口与网卡驱动交互的中间文件"(当然这是针对网络编程,socket不只做网络编程,但也可以理解就是接口与驱动交互的中间文件)。
你发送网络数据先把数据写入到这个文件中,再有系统读取此文件使用硬件驱动发出数据;
接收数据也是有驱动接收到数据后内部缓存,做了包验证和排序之后再写入到socket文件中,你这是就可以通过socket api来读取这个数据,在inux还可以使用系统的read函数来接收网络数据。
为什么需要这个中间文件,第一个原因就是封装TCP/IP协议了,第二个原因是我们的Linux和windows系统都是非实时系统,所有指令不是立刻执行的,需要交由系统来调度执行,那必然要有有缓冲存储的地方。
下面我们通过一段http客户端连接的代码来理解下socket,代码是windows版本,linux版本基本只需要改下头文件。
/示例通过http协议访问 http://edu.csdn.net/course/detail/4358 夏曹俊课程
#include <iostream>
#include <windows.h>
using namespace std;
//在windows网络编程中需要引入库
#pragma comment(lib, "wsock32.lib")
int main(int argc, char *argv[])
{
//在windows网络编程中导入库,linux中不需要
WSADATA Ws;
if (WSAStartup(MAKEWORD(2, 2), &Ws) != 0)
{
cout << "Init Windows Socket Failed::" << GetLastError() << endl;
return -1;
}
//通过域名获取IP地址
HOSTENT *host_entry = gethostbyname("edu.csdn.net");
if (!host_entry){ return -1; }
//将网络字节序的网络地址转为本地字节序
char *serverIP = inet_ntoa(*((struct in_addr *)host_entry->h_addr));
cout << "server IP is " << serverIP << endl;
//创建socket并且绑定了TCP协议
int hsocket = socket(AF_INET, SOCK_STREAM, 0);
//socket创建失败,一般都市系统资源没有了,或者没有权限
if (hsocket == INVALID_SOCKET)
{
cout << "Create Socket Failed::" << GetLastError() << endl;
return -2;
}
//连接http服务器,也就是进行TCP三次握手
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(80); //指定端口号,http协议默认80端口
servAddr.sin_addr.S_un.S_addr = inet_addr(serverIP);
if (connect(hsocket, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
cout << "Connect error" << endl;
return -3;
}
else cout << "Connected "<<serverIP<<" successed!" << endl;
//发出页面URL请求数据
//http://edu.csdn.net/course/detail/4358
char req[] = "GET /course/detail/4358 HTTP/1.0\r\n\r\n";
cout << req << endl;
//注意send并不能保证你指定大小的数据它能够全部发送,
if (send(hsocket, req, (int)strlen(req), 0) < 0)
{
cout << "send request error" << endl;
return -4;
}
cout << "sended request success!" << endl;
//接收数据的缓冲,应为是字符串所以结尾要加\0,我们一开始就将它全部置0
char buffer[10000] = {0};
int len;
//注意,recv并不能保证一次把所有数据收到
if ( recv(hsocket, buffer, sizeof(buffer)-1, 0) <0)
{
cout << "read error" << endl;
exit(1);
}
cout << buffer << endl;
getchar();
return 0;
}
更多内容可以到网上搜索“夏曹俊”获取我的课程