本文实现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;
}
运行结果:
如果出现无法连接请检查ip和port字节序的转换问题。htons和htonl等问题。