面向连接的系统调用
面向无连接的系统调用
1.Winsock的打开
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
成功返回0,失败返回不同的错误信息。
2.服务器建立套接字
SOCKET socket(int af, int type, int protocol);
成功返回套接字对象,失败返回INVALID_SOCKET
af:说明套接口要使用的协议地址族,目前只提供AF_INET表示互联网(IP)协议。
type:描述套接字的类型,只能是SOCK_STREAM,SOCK_DGRAM,SOCK_RAW 3个协议中的一个,分别表示流套接字,数据报套接字和原始套接字
protocol:该套接字使用的特定通信协定(如果使用者不指定则为0)
3.服务器绑定端口
int bind(SOCKET s, const sockaddr FAR* name, int namelen);
成功返回0,失败返回SOCKET_ERROR
s:表示未绑定的套接字的对象名,他是socket()函数调用成功时返回的值。
name:套接字的地址值,是一个与指定协议有关的地址结构指针,这个地址必须是执行这个程式所在的机器的IP地址,
在winsock中使用sockaddr_in结构指定IP地址和端口信息,定义如下:
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
其中sin_family必须为AF_INET,指明使用的是IP地址族;sin_port和sin_addr分别是以网络字节顺序表示的16位端口号和32位IP地址,
sin_zero字段一般为0;
namelen:地址参数name的长度。
4.客户端提出连接申请
int PASCAL FAR connection(SOCKET s, const struct sockaddr FAR* name, int namelen);
s:socket的识别码
name:socket想要连接的对方地址
namelen:name的长度监听
当服务端的套接字对象绑定完成之后,服务器端需要一个监听的队列来接收客户端的连接请求.listen()函数是服务器端的套接字进入监听状态。
int listen(SOCKET s, int backlog);
成功返回0,失败返回SOCKET_ERROR
s:表明一个已经绑定了的地址,需要建立监听的套接字
backlog:指定正在等待连接的最大连接个数。
服务器端调用accept()函数完成建立连接,为了知道什么时候客户端提出连接要求,从而服务器端的套接口在恰当的时候调用accept()函数完成连接的建立,需要使用
WSAAsyncSelect()函数,让系统主动通知有客户端提出连接请求了。
int WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent);
s:套接字对象
hWnd:接收消息的窗口句柄
wMsg:传给窗口的消息
IEvent:被注册的网络时间,也即是应用程序向窗口发送消息的网路事件。该值为下列值FD_READ,FD_WRITE,FD_OOB,FD_CONNECT,FD_CLOSE的组合
可以再窗口处理自定义消息函数中使用以下结构来响应Socket的不同事件:
switch(lParam)
{
case FD_READ:
...
bread;
case FD_WRITE:
...
break;
...
}
5.服务器端接受客户端的连接请求
SOCKET accept(SCOKET s, struct sockaddr FAR* addr, int FAR* addrlen);
调用成功,返回一个新的套接字对象与客户端的套接字相通。失败返回INVALID_SOCKET.
s:Socket的识别码
addr:存放来连接的客户端的地址
addrlen:addr的长度
6.数据的传送
int send(SOCKET s, const char FAR* buf, int len, int flags);
成功返回发送资料的长度,失败返回SOCKET_ERROR
s:socket的识别码
buf:存放要传送的资料的暂存区
len:buf的长度
flags:此函数被调用的方式
int recv(SOCKET s, char FAR* buf, int len, int flags);
成功返回接收资料的长度,失败返回SOCKET_ERROR
s:socket的识别码
buf:存放要接收的资料的暂存区
len:buf的长度
flags:此函数被调用的方式输入缓存内有效的资料,但其数量不超过len的大小
7.关闭套接字
int closesocket(SOCKET s);
8.关闭Winsock
int WSACleanup(void); //对应每个WSAStartup()函数,必须有一个WSACleanup()函数的调用
实例代码:
1)服务器端代码
1 #include <WinSock2.h> 2 #include <iostream> 3 #include <cstdlib> 4 #pragma comment(lib,"ws2_32.lib") 5 using namespace std; 6 7 #define PORT 5000 8 int main() 9 { 10 int port = PORT; 11 WSADATA wsaData; 12 if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0) 13 { 14 perror("winsock load failed!\n"); 15 return 1; 16 } 17 //创建套接字 18 SOCKET sListen = socket(AF_INET, SOCK_STREAM, 0); 19 if (sListen == INVALID_SOCKET) 20 { 21 perror("create socket faild! \n"); 22 return 1; 23 } 24 //建立服务器地址 25 struct sockaddr_in serv; 26 struct sockaddr_in client; 27 serv.sin_family = AF_INET; 28 //把一个双字节主机字节顺序的数据转换为网络字节顺序 29 serv.sin_port = htons(port); 30 //把四字节主机字节顺序转换为网络字节顺序,INADDR_ANY为系统指定的IP地址 31 serv.sin_addr.s_addr = htonl(INADDR_ANY); 32 if (bind(sListen, (LPSOCKADDR)&serv, sizeof(serv)) == SOCKET_ERROR) 33 { 34 perror("bind socket failed ! \n"); 35 return 1; 36 } 37 //进入监听状态 38 if (listen(sListen,5) == SOCKET_ERROR) 39 { 40 perror("listen socket failed! \n"); 41 return 1; 42 } 43 //进入循环等待客户端连接 44 int iLen = sizeof(client); 45 while(1) 46 { 47 SOCKET sAccept = accept(sListen, (LPSOCKADDR)&client, &iLen); 48 if (sAccept == INVALID_SOCKET) 49 { 50 perror("accept socket failed! /n"); 51 break; 52 } 53 printf("accepted client IP:[%s],port:[%d]\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port)); 54 55 //给连接的客户发消息 56 char buf[] = "hello client,i am server!"; 57 int iSend = send(sAccept,buf,sizeof(buf),0); 58 if (iSend == SOCKET_ERROR) 59 { 60 perror("send buf failed \n"); 61 break; 62 } 63 else if (iSend == 0) 64 { 65 break; 66 } 67 else 68 printf("send()byte:%d \n",iSend); 69 printf("********************\n"); 70 char recv_buf[1024] = {0}; 71 int recv_len = recv(sAccept,recv_buf,sizeof(recv_buf),0); 72 if (recv_len == SOCKET_ERROR) 73 { 74 perror("server recv failed \n"); 75 return 1; 76 } 77 else{ 78 printf("recv from client:%s \n",recv_buf); 79 } 80 } 81 82 83 closesocket(sListen); 84 WSACleanup(); 85 //return 0; 86 }
2)客户端代码
1 #include <WinSock2.h> 2 #include <iostream> 3 #include <cstdlib> 4 #pragma comment (lib,"ws2_32.lib") 5 using namespace std; 6 7 #define PORT 5000 8 #define BUFFER 1024 9 int main(int argc, char* argv[]) 10 { 11 //初始化socket 12 WSADATA wsaData; 13 if(0 != WSAStartup(MAKEWORD(2,2),&wsaData)) 14 { 15 perror("winsock load failed \n"); 16 return 1; 17 } 18 //建立客户端流套接字 19 SOCKET client = socket(AF_INET,SOCK_STREAM,0); 20 if (client == INVALID_SOCKET) 21 { 22 perror("create socket failed\n"); 23 return 1; 24 } 25 //连接服务端 26 struct sockaddr_in serv; 27 serv.sin_family = AF_INET; //需要连接的服务器地址信息 28 int port = PORT; 29 serv.sin_port = htons(port); 30 serv.sin_addr.s_addr = inet_addr(argv[1]); //将命令行的IP地址转化为二进制表示的网络字节书序IP地址 31 if (connect(client,(const struct sockaddr*)&serv,sizeof(serv)) == INVALID_SOCKET) 32 { 33 perror("connect faild\n"); 34 return 1; 35 } 36 else 37 { 38 char buf[BUFFER] = {0}; 39 int iLen = recv(client,buf,sizeof(buf),0); 40 if (iLen == SOCKET_ERROR) 41 { 42 perror("recv data failed \n"); 43 return 1; 44 } 45 printf("recv() data from server:%s\n",buf); 46 char send_buf[] = "hello server, i am client."; 47 int send_len = send(client,send_buf,sizeof(send_buf),0); 48 if (send_len == SOCKET_ERROR) 49 { 50 perror("client send failed \n"); 51 return 1; 52 } 53 else 54 printf("send()bytes: %d\n",send_len); 55 } 56 closesocket(client); 57 WSACleanup(); 58 printf("please wait.........."); 59 while(1); 60 61 }