多个windows客户端与linux服务端socket通信,epoll实现i/o复用

本文实现Windows客户端与linux服务器之间的通信,socket网络编程。

实现多个客户端连接一个服务器采用的方法不是用while循环,而是更高效的epoll i/o复用,当然你也可以用select 和poll。

windows客户端(vs2013):

#include <stdio.h>
#include <Windows.h>
#include <sys/types.h> 

#include <io.h>
#include<signal.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[]) 
{

	WSADATA s;
	SOCKET ClientSocket;
	struct sockaddr_in ClientAddr; 
	int ret = 0;
	char SendBuffer[MAX_PATH]; 
	/*socket编程要调用各种socket函数,但是需要库Ws2_32.lib和头文件Winsock2.h,这里的WSAStartup就是为了向操作系统说明,我们要用哪个库文件*/
	
	if (WSAStartup(MAKEWORD(2, 2), &s) != 0) 
	{
		printf("Init Windows Socket Failed! Error: %d\n", GetLastError());
		getchar();
		return -1;
	}
	
	ClientSocket = socket(AF_INET, SOCK_STREAM, 0); //创建套接字
	if (ClientSocket == INVALID_SOCKET)
	{
		printf("Create Socket Failed! Error: %d\n", GetLastError());
		getchar();
		return -1;
	}

	ClientAddr.sin_family = AF_INET;
	ClientAddr.sin_addr.s_addr = inet_addr("192.168.80.130"); //这个ip为linux虚拟机的ip
	ClientAddr.sin_port = htons(5000); 
	memset(ClientAddr.sin_zero, 0X00, 8); 

	ret = connect(ClientSocket,(struct sockaddr*)&ClientAddr,sizeof(ClientAddr));//主动发起连接
	if (ret == SOCKET_ERROR)
	{
		printf("Socket Connect Failed! Error:%d\n", GetLastError());
		getchar();
		return -1;
	}
	else
	{
		printf("Socket Connect Succeed!\n");
	}
	
	while (1)
	{
		printf("Input Data: ");
		scanf("%s", &SendBuffer);
		ret = send(ClientSocket, SendBuffer, (int)strlen(SendBuffer), 0);
		if (ret == SOCKET_ERROR)
		{
			printf("Send Information Failed! Error:%d\n", GetLastError());
			getchar();
			break;
		}	
	}
		
	closesocket(ClientSocket);		
	WSACleanup();
	getchar();
	return 0;
}

linux服务端:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
//#include<netinet.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<sys/epoll.h>
void setnonblocking(int sockfd)//设置非阻塞线程
{
	fcntl(sockfd,F_SETFL,fcntl(sockfd,F_GETFD,0)|O_NONBLOCK);
	
}
void addfd(int epollfd,int fd,bool enable_et)//将事件fd添加到监听队列
{
	struct epoll_event ev;
	ev.data.fd =fd;
	ev.events =EPOLLIN;
	if(enable_et)
	ev.events =EPOLLIN |EPOLLET;
	epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
	setnonblocking(fd);

}
int main()
{
    
    int listenfd =socket(AF_INET,SOCK_STREAM,0);
    if(listenfd<0)
    {
        printf("listenfd error\n");
        exit(0);
    }
    
    
    struct sockaddr_in servaddr;
    servaddr.sin_family =AF_INET;
    servaddr.sin_port =htons(5000);
    servaddr.sin_addr.s_addr =htonl(INADDR_ANY);//htonl从主机字节序转换成网络字节序

    bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    
    printf("start wait accept...\n");
    if(listen(listenfd,5))
    {
        printf("listening...");
    }
    struct sockaddr_in peeraddr;
    socklen_t peerlen =sizeof(peeraddr);
    int conn;
	int n =0;
	int epfd =epoll_create(50);

	
	struct epoll_event events[50];
	addfd(epfd,listenfd,true);
	while(1)
	{
		int epoll_events_count =epoll_wait(epfd,events,50,-1);
		if(epoll_events_count<0)break;

		for(n=0;n<epoll_events_count;++n)
		{
			int sockfd =events[n].data.fd;

		if(sockfd==listenfd)//如果是监听fd,则表示有新的客户端请求链接
		{
			int client =accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen);
			if(client<0)
			{
				printf("accept...\n");
				continue;
			}
			write(client,"ok",2);
			printf("cli =%d\n",client);
			setnonblocking(client);
			addfd(epfd,client,true);
		}
			else//否则监听队列的fd有事情发生需要处理
			{
				
				char buffer[100]="";
				int sockfd_r=events[n].data.fd;
				write(sockfd_r,"ok",2);
				read(sockfd_r,buffer,125);
				printf("%s\n",buffer);
				
			}
		}
	}


    return 0;
}

运行结果:

多个windows客户端与linux服务端socket通信,epoll实现i/o复用

如果出现无法连接请检查ip和port字节序的转换问题。htons和htonl等问题。