#include <stdio.h> #include <winsock.h> #include <string.h> #pragma comment (lib, "ws2_32") #define SERVER_PORT 8888 /*服务端口*/ #define MAX_MSG_SIZE 2048 /*缓冲区大小*/ #define BACKLOG 5 /*等待服务的最大数*/
int Server_Proc(int sock) { int n; char msg[MAX_MSG_SIZE]; n = recv(sock, msg, MAX_MSG_SIZE, 0); msg[n] = 0; printf("%s\n", msg); strcpy(msg, "hi, i am server!"); n = send(sock, msg, strlen(msg), 0); closesocket(sock); return 1; }
int main() { int ser_sock, /*服务器SOCKET*/ cli_sock; /*客户端SOCKET*/ int addrlen; /*地址长度*/ char hostname[255]; /*主机名*/ PHOSTENT hptr; /*主机地址*/
struct sockaddr_in ser_addr, /*服务器地址*/ cli_addr; /*客户端地址*/
WSADATA WSAData; if(WSAStartup(MAKEWORD(2,2), &WSAData) != 0) { fprintf(stderr, "WSAStartup failed:%d\n", WSAGetLastError()); exit(1); }
/*获得本地主机名,并输出IP地址*/ if(gethostname(hostname, sizeof(hostname)) != 0) { errno = GetLastError(); fprintf(stderr,"gethostname Error:%d\n", errno); return 1; } hptr = gethostbyname(hostname); printf("IP: %s\n", inet_ntoa(*(struct in_addr*) *hptr->h_addr_list));
/*创建连接的SOCKET*/ ser_sock = socket(AF_INET, SOCK_STREAM, 0); if(ser_sock < 0) { fprintf(stderr, "socket error : %d\n", GetLastError()); exit(1); } /*初始化服务器地址*/ addrlen = sizeof(struct sockaddr_in); memset(&ser_addr, 0, addrlen); ser_addr.sin_family = AF_INET; ser_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); ser_addr.sin_port = htons(SERVER_PORT);
/*绑定socket和本地地址*/ if(bind(ser_sock, (struct sockaddr*)&ser_addr, addrlen)<0) { fprintf(stderr, "Bind error:%d\n", GetLastError()); exit(1); }
/*侦听客户端请求*/ if(listen(ser_sock, BACKLOG) < 0) { fprintf(stderr, "listen error: %d\n", GetLastError()); closesocket(ser_sock); exit(1); }
printf("waiting for client....\n"); while(1) { cli_sock = accept(ser_sock, (struct sockaddr*)&cli_addr, &addrlen); /*对连接建立请求的响应,返回新的socket,*/ if(cli_sock <= 0) fprintf(stderr, "Accept error:%d\n", GetLastError()); else Server_Proc(cli_sock); } closesocket(ser_sock); WSACleanup(); return 0; }
|
工作流程:
服务器端调用socket初始化,bind 端口和地址,listen 客户端的请求,再调用accept 阻塞等待客户连接请求,处于监听端口状态;客户端调用socket初始化,再调用connect请求连接服务器,连接成功后,服务器端也从accept返回,返回一个新的cli_socket,用于跟客户端进行通信;通信完后,客户端关闭socket,服务器端关闭cli_socket。由于服务器端有个while(1),accept处于一直等待状态,所以还可以和新的客户端通信。
函数说明:
(1)socket 创建套接字
原型:SOCKET socket (int af, int type, int protocol)
af指定通信协议类型,通常为AF_INET; type指定套接字类型,流式套接字为SOCK_STREAM;protocol为指定套接字使用的特定协议,通常为IPPROTO_IP,值为0. 成功后返回新创建的套接字描述符。
(2)closesocket 关闭套接字
原型: int closesocket(SOCKET s)
参数是要关闭的套接字描述符,成功返回0
(3)bind 绑定本地地址和套接字
原型:int bind (SOCKET s, const struct sockaddr FAR *addr, int namelen)
s是要绑定的套接字描述符,addr指定sockaddr结构的套接字地址, namelen是套接字地址结构长度。成功后返回0
(4)listen 监听端口的连接建立请求
原型:int listen(SOCKET s, int backlog)
s为要监听的套接字描述符,backlog是客户连接请求队列最多容纳backlog个客户,成功返回0.
(5)accept 对建立连接请求的响应
原型:SOCKET accept (SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen)
s为要监听的套接字描述符;addr返回新创建的套接字地址结构, addrlen该地址结构的长度,成功返回新创建的套接字描述符。
一个结构体:
struct sockaddr_in { short sin_family; //网络地址类型,AF_INET u_short sin_port; //使用的端口号 struct in_addr sin_addr; //使用的IP地址,INADDR_ANY表示所有IP地址 char sin_zero[8]; //填充字段,为了使sockaddr_in可转化为sockaddr };
|
阅读(835) | 评论(0) | 转发(0) |