序言:
这几天,看看网络编程,以前一直只写过很简单的网络,一直对其具有畏惧心理,这几天就硬下头皮,看看怎么应用,暂时不关心,他底层是怎么实现的。也没研究网络方向的驱动模式。我就看了下windows下面和linux下面的各自调用方式,感觉大体是一致的。
实体:
1.头文件。
在windows中需要引入头文件 #include
在linux里面基本山需要引入头文件 #include, #include #include
2.链接库
在windows下面需要主动的链接ws2_32.lib库文件。
-
#pragma comment(lib,"ws2_32.lib")
在linux中并不需要,linux默认没有动态调用,相关的函数实现在libc.a里面。属于默认的链接选项。
3.初始化
在windows下面需要初始化,windows下面是通过动态链接的方式条用socket的,所以需要告诉你要调用的链接库的版本,操作系统会帮你加载并初始化该dll。
函数为 :
-
int PASCAL FAR WSAStartup( __in WORD wVersionRequired, __out LPWSADATA lpWSAData);
-
int PASCAL FAR WSACleanup(void);
4.结构体
在windows和linux里面于socket相关的结构体基本一样。我们再次只是说明基本的。结构体sockaddr_in,windows定义为
-
struct sockaddr_in {
short sin_family;//表示网络介质,最常见的是AF_INET表示互联网
u_short sin_port; //端口,需要的是网络字节序一般通过htons函数取的
struct in_addr sin_addr; //本机的IP地址,也需要网络字节序,一般通过inet_addr("IP")取得
char sin_zero[8];
};
-
//保存网络字节序的ip地址
-
typedef struct in_addr {
-
union {
-
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
-
struct { USHORT s_w1,s_w2; } S_un_w;
-
ULONG S_addr;
-
} S_un;
-
-
//有了这个宏定义就可以使得linux和windows的形式是一样的。
-
-
#define s_addr S_un.S_addr /* can be used for most tcp & ip code */
linux里面的定义为:
-
struct sockaddr_in {
-
sa_family_t sin_family; /* address family: AF_INET */
-
in_port_t sin_port; /* port in network byte order */
-
struct in_addr sin_addr; /* internet address */
-
};
-
-
/* Internet address. */
-
struct in_addr {
-
uint32_t s_addr; /* address in network byte order */
-
};
5.函数
在windows和linux里面关于socket的函数时一致的只是windows里面宏定义了一个socket描述符。如下
-
int socket(int domain, int type, int protocol);
-
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
-
int listen(int sockfd, int backlog);
-
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-
ssize_t recv(int s, void *buf, size_t len, int flags);
-
ssize_t send(int s, const void *buf, size_t len, int flags);
其中listen中的参数backlog表示的是,正在或者已经经过了三次握手,但是没有经过应用程序处理的个数(也就是没有经过accept,分配描述符的)。
所以一个典型的server的代码为:
-
#ifdef WIN32
-
#include<WinSock.h>
-
#include
-
#pragma comment(lib,"ws2_32.lib")
-
#else
-
#include<sys/types.h>
-
#include<sys/socket.h>
-
#include<netinet/in.h>
-
typedef int SOCKET;
-
#endif
-
#define PORT 2048
-
#define BACKLOG 10
-
int main()
-
{
-
#ifdef WIN32
-
WSADATA WSAData;
-
::WSAStartup(MAKEWORD(1,1),&WSAData);
-
#endif
-
-
SOCKET sock,sock_client;
-
sock = socket(AF_INET,SOCK_STREAM, 0);
-
-
struct sockaddr_in serveraddr, client_addr;
-
serveraddr.sin_family = AF_INET;
-
serveraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
-
serveraddr.sin_port = htons(PORT);//端口和IP得转化成网络字节序,也就是bigendian
-
memset(serveraddr.sin_zero, 0 , sizeof(serveraddr.sin_zero));
-
bind(sock, (struct sockaddr*)&serveraddr,sizeof(serveraddr));
-
-
listen(sock, BACKLOG);
-
int sin_size = sizeof(client_addr);
-
-
sock_client = accept(sock, (struct sockaddr*)&client_addr, &sin_size);
-
char buf[] = "hello world!";
-
send(sock_client,buf, strlen(buf), 0);
-
#ifdef WIN32
-
::closesocket(sock);
-
::closesocket(sock_client);
-
::WSACleanup();
-
#else
-
close(sock_client);
-
close(sock);
-
#endif
-
}
上边代码忽略了出现错误的情况的错误处理。因为windows和linux的返回值往往不一样。所以这些细节太麻烦就不想写了。
总结:
其实网络编程的基础还是很简单的,复杂的是网络的优化,和所有方向的关于多线程或者多进程的处理。
阅读(1905) | 评论(0) | 转发(0) |