这是一个常常用到的老掉牙的主题了,为了之后用到方便,因此稍微注释了一下而后放上来,代码是本人修改过的,因此也就选成了“原创”。其实如今作码农的,又有多少基础模块能说大致的代码都是本身搞出来的呢?这个“原创"的界定很难!好了,废话很少说,贴代码,基本上用VS的拷过去也是能直接运行的。服务器
服务器普通实现代码并发
<span style="color:#3366ff;">#include <stdio.h> #include <Winsock2.h> #pragma comment(lib,"Ws2_32.lib")//链接Sockets相关库 void main() { SOCKET socket1; WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 1), &wsaData)) //初始化 { printf("Winsock没法初始化!\n"); WSACleanup(); return; } printf("服务器开始建立SOCKET。\n"); struct sockaddr_in local;//本机地址相关结构体 struct sockaddr_in from;//客户端地址相关结构体 int fromlen = sizeof(from); local.sin_family = AF_INET; local.sin_port = htons(27015); ///监听端口 local.sin_addr.s_addr = INADDR_ANY; ///本机 socket1 = socket(AF_INET, SOCK_DGRAM, 0); bind(socket1, (struct sockaddr*)&local, sizeof(local));//绑定SOCKET,此步关键 char buffer[1024] = "\0"; if (recvfrom(socket1, buffer, sizeof(buffer), 0, (struct sockaddr*)&from, &fromlen) != SOCKET_ERROR)//阻塞接受客户端的请求 { printf("链接成功,开始发送数据\n"); } while (1) { sendto(socket1, buffer, sizeof(buffer), 0, (struct sockaddr*)&from, fromlen);//发数据给客户端,因为是 Sleep(200); } closesocket(socket1); WSACleanup(); }</span>
#include <stdio.h> #include <Winsock2.h> #pragma comment(lib,"Ws2_32.lib")//链接Sockets相关库 void main() { SOCKET socket1; WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 1), &wsaData)) //初始化 { printf("Winsock没法初始化!\n"); WSACleanup(); return; } printf("客户端开始建立SOCKET。\n"); struct sockaddr_in server; int len = sizeof(server); server.sin_family = AF_INET; server.sin_port = htons(27015); ///server的监听端口 server.sin_addr.s_addr = inet_addr("127.0.0.1"); ///server的地址 socket1 = socket(AF_INET, SOCK_DGRAM, 0); char buffer[1024] = "haha\0"; if (sendto(socket1, buffer, sizeof(buffer), 0, (struct sockaddr*)&server, len) != SOCKET_ERROR)//发送信息给服务器,发送完进入等待,表明服务器在客户端启动前必须是等待状态 { printf("发送请求,等待客户端接受并发送数据\n"); } while (1) { Sleep(100); if (recvfrom(socket1, buffer, sizeof(buffer), 0, (struct sockaddr*)&server, &len) != SOCKET_ERROR) printf("从客户端接收到的数据:%s\n", buffer); } closesocket(socket1); WSACleanup(); }
在程序设计中一般但愿对于数据交互方有没有数据传来作出反应,而不是单纯的阻塞等待在那里。这个时候能够用select先进行探测,一探测到有数据过来才调用recvfrom,若是超过期间则作出相应的超时处理,实现须要在上面的代码中recvfrom(原程序该函数阻塞)处稍做修改,修改代码以下:socket
fd_set readfds; FD_ZERO(&readfds);//将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,若是不清空,因为在系统分配内存空间后,一般并不做清空处理,因此结果是不可知的 FD_SET(socket1, &readfds); //用于在文件描述符集合中增长一个新的文件描述符。 struct timeval tv_out; tv_out.tv_sec = 5;//等待5秒 tv_out.tv_usec = 0; int selright=select(socket1 + 1, &readfds, NULL, NULL, &tv_out); if (selright<=0)//为0时为超时,小于0时为错误,这两种状况皆非咱们所想,故作出相同的处理 { printf("链接失败"); return; } else { if (recvfrom(socket1, buffer, sizeof(buffer), 0, (struct sockaddr*)&from, &fromlen) != SOCKET_ERROR)//阻塞接受客户端的请求 { printf("链接成功,开始发送数据\n"); } }固然若是但愿循环等待,则每次都必须从新设置readfds