windows下的socket网络编程
2015年07月01日[TOC] 博客园文章地址 http://www.cnblogs.com/oloroso/archive/2015/07/01/4613296.html
windows下的socket网络编程
已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket
网路通信的例子,以便以后用到的时候有个参考。
windows下使用winsock
编程与linux/unix
的区别在于windows下需要先有一个初始化
的操作,结束的时候需要一个清理
的操作。还有windows下编译的时候需要连接ws32_lib
库。
大致过程如下
-
1、初始化
/加载Winsock DLL/
WSADATA wsd;
if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
printf(“Winsock 初始化失败!\n”);
return 1;
}
-
2、socket相关函数调用
socket(…)
bind(…)
listen(…)
connect(…)
accept(…)
send/sendto
recv/recvfrom
-
3、清理
WSACleanup();
clinet.c 客户端
客户端的流程很简单。
- 1、先是使用
socket
函数产生一个打开的socket
文件描述符。 - 2、使用
connect
函数去连接服务端 - 3、使用
read/recv
等读文件函数从服务端接收数据,使用write/send
等写文件的函数向服务端发送数据
上面是典型的TCP
编程流程,如果是UDP
的话不需要connect
去连接服务端直接使用sendto
函数来发送数据,使用recvfrom接收来自服务器的数据
server.c 服务器端
服务器端的流程比客户端稍微复杂一点
- 1、调用
socket
打开一个socket句柄 - 2、调用
bind
来绑定socket句柄到一个网口的某个端口 - 3、调用
listen
来设置(启用)监听 - 4、调用
accept
来等待客户端的连接
上面是典型的TCP
编程流程,如果是UDP
的,那么不需要3,4
这两部,直接使用recvfrom
来接收客户端发过来的数据即可。
UDP通信的实现
我这里没有写TCP
的,因为都是局域网内,就简单的写了个。
这里是在虚拟机里面测试的截图,代码见最后。
代码如下
这是TCP的,UDP的就不贴了。
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <winsock2.h> #include <stdio.h> #include <stdlib.h>#pragma comment(lib , “ws2_32.lib”)
#define BUFSIZE 4096 /缓冲区大小/
int main_client(int argc , char *argv[]) { WSADATA wsd; SOCKET sClient; char Buffer[BUFSIZE]; int ret; struct sockaddr_in server; unsigned short port; struct hostent *host = NULL;
</span><span style="color: #0000ff;">if</span> (argc < <span style="color: #800080;">3</span><span style="color: #000000;">) { printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">Usage:%s IP Port\n</span><span style="color: #800000;">"</span> , argv[<span style="color: #800080;">0</span><span style="color: #000000;">]); </span><span style="color: #0000ff;">return</span> -<span style="color: #800080;">1</span><span style="color: #000000;">; } </span><span style="color: #008000;">/*</span><span style="color: #008000;">加载Winsock DLL</span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">if</span> (WSAStartup(MAKEWORD(<span style="color: #800080;">2</span> , <span style="color: #800080;">2</span>) , &wsd) != <span style="color: #800080;">0</span><span style="color: #000000;">) { printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">Winsock 初始化失败!\n</span><span style="color: #800000;">"</span><span style="color: #000000;">); </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">; } </span><span style="color: #008000;">/*</span><span style="color: #008000;">创建Socket</span><span style="color: #008000;">*/</span><span style="color: #000000;"> sClient </span>=<span style="color: #000000;"> socket(AF_INET , SOCK_STREAM , IPPROTO_TCP); </span><span style="color: #0000ff;">if</span> (sClient ==<span style="color: #000000;"> INVALID_SOCKET) { printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">socket() 失败: %d\n</span><span style="color: #800000;">"</span><span style="color: #000000;"> , WSAGetLastError()); </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">; } </span><span style="color: #008000;">/*</span><span style="color: #008000;">指定服务器地址</span><span style="color: #008000;">*/</span><span style="color: #000000;"> server.sin_family </span>=<span style="color: #000000;"> AF_INET; port </span>= atoi(argv[<span style="color: #800080;">2</span><span style="color: #000000;">]); server.sin_port </span>=<span style="color: #000000;"> htons(port); server.sin_addr.s_addr </span>= inet_addr(argv[<span style="color: #800080;">1</span><span style="color: #000000;">]); </span><span style="color: #0000ff;">if</span> (server.sin_addr.s_addr ==<span style="color: #000000;"> INADDR_NONE) { host </span>= gethostbyname(argv[<span style="color: #800080;">1</span>]); <span style="color: #008000;">//</span><span style="color: #008000;">输入的地址可能是域名等</span> <span style="color: #0000ff;">if</span> (host ==<span style="color: #000000;"> NULL) { printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">无法解析服务端地址: %s\n</span><span style="color: #800000;">"</span> , argv[<span style="color: #800080;">1</span><span style="color: #000000;">]); </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">; } CopyMemory(</span>&<span style="color: #000000;">server.sin_addr , host</span>->h_addr_list[<span style="color: #800080;">0</span><span style="color: #000000;">] , host</span>-><span style="color: #000000;">h_length); } </span><span style="color: #008000;">/*</span><span style="color: #008000;">与服务器建立连接</span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">if</span> (connect(sClient , (<span style="color: #0000ff;">struct</span> sockaddr*)&<span style="color: #000000;">server , </span><span style="color: #0000ff;">sizeof</span>(server)) ==<span style="color: #000000;"> SOCKET_ERROR) { printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">connect() 失败: %d\n</span><span style="color: #800000;">"</span><span style="color: #000000;"> , WSAGetLastError()); </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">; } </span><span style="color: #008000;">/*</span><span style="color: #008000;">发送、接收消息</span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">for</span><span style="color: #000000;"> (;;) { </span><span style="color: #008000;">//</span><span style="color: #008000;">从标准输入读取要发送的数据 </span><span style="color: #008000;">//</span><span style="color: #008000;">gets_s(Buffer,BUFSIZE);</span>
gets(Buffer); //向服务器发送消息 ret = send(sClient , Buffer , strlen(Buffer) , 0); if (ret == 0) { break; } else if (ret == SOCKET_ERROR) { printf(“send() 失败: %d\n“ , WSAGetLastError()); break; } printf(“Send %d bytes\n“ , ret); //接收从服务器来的消息 ret = recv(sClient , Buffer , BUFSIZE , 0); if (ret == 0) { break; } else if (ret == SOCKET_ERROR) { printf(“recv() 失败: %d\n“ , WSAGetLastError()); break; } Buffer[ret] = ‘\0‘; printf(“Recv %d bytes:\n\t%s\n“ , ret , Buffer);
} </span><span style="color: #008000;">//</span><span style="color: #008000;">用完了,关闭socket句柄(文件描述符)</span>
closesocket(sClient); WSACleanup(); //清理 return 0; }
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <winsock2.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 #pragma comment(lib , “ws2_32.lib”) 6 7 8 #define DEFAULT_BUFFER 4096 /缓冲区大小/ 9 10 11 /与客户机通信的线程函数/ 12 DWORD WINAPI ClientThread(LPVOID lpParam) 13 { 14 SOCKET sock = (SOCKET)lpParam; 15 char Buffer[DEFAULT_BUFFER]; 16 int ret , nLeft , idx; 17 while (1) { 18 /接收来自客户机的消息/ 19 ret = recv(sock , Buffer , DEFAULT_BUFFER , 0); 20 if (ret == 0) 21 break; 22 else if (ret == SOCKET_ERROR) { 23 printf(“recv() 失败: %d\n“ , WSAGetLastError()); 24 break; 25 } 26 Buffer[ret] = ‘\0‘; 27 printf(“Recv: %s\n“ , Buffer); //打印接收到的消息 28 29 30 nLeft = ret; 31 idx = 0; 32 while (nLeft > 0) { 33 /向客户机发送回应消息/ 34 ret = send(sock , &Buffer[idx] , nLeft , 0); 35 if (ret == 0) 36 break; 37 else if (ret == SOCKET_ERROR) { 38 printf(“send() 失败: %d\n“ , WSAGetLastError()); 39 break; 40 } 41 nLeft -= ret; 42 idx += ret; 43 } 44 } 45 return 0; 46 } 47 48 int main_server(int argc , char argv) 49 { 50 WSADATA wsd; 51 HANDLE hThread; 52 DWORD dwThread; 53 SOCKET sListen , sClient; 54 int AddrSize; 55 unsigned short port; 56 struct sockaddr_in local , client; 57 58 if (argc < 2) { 59 printf(“Usage:%s Port\n“ , argv[0]); 60 return -1; 61 } 62 63 /加载Winsock DLL/ 64 if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) { 65 printf(“WinSock 初始化失败!\n“); 66 return 1; 67 } 68 69 /创建Socket/ 70 sListen = socket(AF_INET , SOCK_STREAM , IPPROTO_IP); 71 if (sListen == SOCKET_ERROR) { 72 printf(“socket() 失败: %d\n“ , WSAGetLastError()); 73 return 1; 74 } 75 76 local.sin_family = AF_INET; 77 local.sin_addr.s_addr = htonl(INADDR_ANY); 78 port = atoi(argv[1]); //获取端口值 79 local.sin_port = htons(port); 80 81 /绑定Socket/ 82 if (bind(sListen , 83 (struct sockaddr)&local , 84 sizeof(local)) == SOCKET_ERROR) { 85 printf(“bind() 失败: %d\n“ , WSAGetLastError()); 86 return 1; 87 } 88 /打开监听/ 89 listen(sListen , 8); 90 91 /在端口进行监听,一旦有客户机发起连接请示 92 就建立与客户机进行通信的线程/ 93 while (1) { 94 AddrSize = sizeof(client); 95 /监听是否有连接请求/ 96 sClient = accept(sListen , 97 (struct sockaddr)&client , 98 &AddrSize); 99 if (sClient == INVALID_SOCKET) { 100 printf(“accept() 失败: %d\n“ , WSAGetLastError()); 101 break; 102 } 103 printf(“接受客户端连接: %s:%d\n“ , 104 inet_ntoa(client.sin_addr) , 105 ntohs(client.sin_port)); 106 107 //创建一个线程去处理 108 hThread = CreateThread(NULL , 0 , ClientThread , 109 (LPVOID)sClient , 0 , &dwThread); 110 111 if (hThread == NULL) { 112 printf(“CreateThread() 失败: %d\n“ , GetLastError()); 113 break; 114 } 115 //处理完后关闭 116 CloseHandle(hThread); 117 } 118 closesocket(sListen); 119 WSACleanup(); //用完了要清理 120 return 0; 121 }
测试代码(main)
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 extern int main_client(int , char); 2 extern int main_server(int , char); 3 4 int main(int c , char v) 5 { 6 if (c == 3) { 7 main_client(c , v); 8 } 9 else { 10 main_server(c , v); 11 } 12 return 0; 13 14 }