【winsock2】windows网络编程 之 TCP/IP Server

Socket网络编程无论是什么平台,都有相似流程;在windows中我们一般使用WinSock2来进行网络通信,当然还有其他网络通信库。

今天具体说下TCP/IP Server的编程流程,具体分为6大步,下面一一解释!

我们需要头文件和库:

#include <WinSock2.h> // Windows Socket  Version 2.2

#pragma comment(lib,"ws2_32.lib") // Windows Socket Version 2.2 [32 bit]

1、初始化 Windows Socket

WSADATA  wsa_data; //用来获取WSA的版本

int   ret = 0;

ret = WSAStartup(MAKEWORD(2,2),&wsa_data); //返回值为0,不等于0 则出错,不过一般不会出错

MAKEWORD(2,2)转化成WSA可以识别的版本Version 2.2

如果返回成功我们也可以通过

LOBYTE(wsa_data,wVersion)

HIBYTE(wsa_data,wVersion)

来已经设置的版本,wVersion是在WinSock2.h里面定义的,所以这里我们不必纠结;

如果出错可以用WSAGetLastError()来获取出错代码,下面也可以同样用这种方法!

2、创建 Socket (套接字)

SOCKET fd_socket; //作为Server的套接字

fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建套接字,如果出错,返回INVALID_SOCKET

如果出错,记得释放已经初始化的socket:WSACleanup();

socket的第一个参数为域;

描述
AF_INET IPv4 因特网域
AF_INET6 IPv6因特网域
AF_UNIX UNIX域
AF_UNSPEC 未指定

我们常用的就是前两个,想了解更多请看《UNIX环境高级编程(APUE)》

socket的第二个参数也有四种:

Type Description
SOCK_DGRAM 长度固定的,无连接的不可靠报文传递
SOCK_RAW IP协议的数据报接口(POSIX.1中为可选)
SOCK_SEQPACKET 长度固定、有序、可靠的面向连接报文传递
SOCK_STREAM 有序、可靠、双向的面向连接字节流

SOCK_DGRAM + IPPROTO_UDP  是UDP/IP的报文类型
SOCK_STREAM + IPPROTO_TCP 是TCP/IP的报文类型
其实我们最后一个参数可以用0代替,0 :default

3、绑定 Socket (套接字)与服务器IP/port

SOCKADDR_IN server_addr; //服务器配置
int  port = 3200; //端口号 
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port); //端口号范围: 0 ~65535
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //INADDR_ANY意思是接受所有IP的连接
ret = bind(fd_socket,(SOCKADDR *)&server_addr,sizeof(SOCKADDR)); //绑定ip域socket,出错返回SOCKET_ERROR

如果出错,记得释放已经初始化的socket:WSACleanup();同时还要关闭socket:closesocket(fd_socket);
htons (host to network short)本机字节转化成网络字节,一般用于端口转化,因为端口是Short型的,server_addr.sin_port = htons(3400);
ntohs (network to host short)网络字节转化为本机字节,ntohs(server_addr.sin_port)
htonl (host to network long)一般用于IP转化,参数常用的是INADDR_ANY
inet_ntoa(server_addr.sin_addr) 把网络ip转化为字符串ip,如 “192.168.1.2”
inet_addr(char *ip) 把字符串ip转化成网络ip,eg: server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");这里表示服务器只接受127.0.0.1的连接;

4、服务器开始监听

ret = listen(fd_socket,5); //5代表最多运行有5个用户在排队,当然也可以设置很多个用户,不过经验证明不要设置太大为好!如果出错返回:SOCKET_ERROR

5、接受客户端的连接

SOCKADDR_IN client_addr; //存储客户端信息
SOCKET fd_client; //客户端套接字
fd_client = accept(fd_socket,(SOCKADDR *)&client_addr,sizeof(SOCKADDR)); //错误返回:INVALID_SOCKET

如果成功,我们就可以开始与客户端进行通信了,如果要与多个客户端进行长时间通信,在UNIX、LINUX里面我们可以用创建进程来处理客户端!
但是在windows环境编程里面,我们用进程来一一处理,后面我会把windows进程编程更新出来!

6、服务器与客户端的通信

6.1 获取客户端的信息

char * inet_ntoa(client_addr.sin_addr); 将网络字节转化为字符串
int ntohs(client_addr.sin_port) 将网络字节转化为本机short字节

inet_ntoa获取本机客户端ip,ntohs获取客户端连接端口

6.2 读取客户端发来的信息

char buff[1024];

memset(buff,0x0,1024); //将buff全部置0

ret = recv(fd_client,buff,1024,0); //1024为buff的size,最后一个参数0是非阻塞模式,出错返回:SOCKET_ERROR

当然,这里我们也可以设置为阻塞模式;

6.3 发送数据到客户端

char send_buff[1024];

memset(send_buff,0x0,1024);

strcpy(send_buff,"xxxxxxxxxxxxxx");

ret = send(fd_client,send_buff,strlen(send_buff),0); //同样,这里的0是非阻塞模式

6.4 关闭客户端套接字

closesocket(fd_client);

如果数据处理完成,不想跟客户端再进行通信了,我们就关闭fd_client;

7、关闭服务器并释放套接字

closesocket(fd_socket);

WSACleanup();

也可以一直重复5.6步!


PS:希望大家多多指点!

文章来自:http://blog.csdn.net/ieczw/article/details/19493311
© 2021 jiaocheng.bubufx.com  联系我们
ICP备案:鲁ICP备09046678号-3