/* * File: TCPEchoClient.c * Author: 云守护 通用客户端 * * Created on 2013年11月13日, 下午3:49 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>#include "DieWithMessage.h"//建立客户端socketint SetupTCPClientSocket(const char *host,const char* service){ //配置想要的地址信息 struct addrinfo addrCriteria; memset(&addrCriteria,0,sizeof(addrCriteria)); addrCriteria.ai_family=AF_UNSPEC; addrCriteria.ai_socktype=SOCK_STREAM; addrCriteria.ai_protocol=IPPROTO_TCP; struct addrinfo *server_addr; //获取地址信息 int retVal=getaddrinfo(host,service,&addrCriteria,&server_addr); if(retVal!=0) DieWithUserMessage("getaddrinfo() failed!",gai_strerror(retVal)); int sock=-1; struct addrinfo *addr=server_addr; while(addr!=NULL) { //建立socket sock=socket(addr->ai_family,addr->ai_socktype,addr->ai_protocol); if(sock<0) continue; if(connect(sock,addr->ai_addr,addr->ai_addrlen)==0) { //链接成功,就中断循环 break; } //没有链接成功,就继续尝试下一个 close(sock); sock=-1; addr=addr->ai_next; } freeaddrinfo(server_addr); return sock;}int main(int argc, char** argv) { if(argc<3||argc>4) { DieWithUserMessage("param","<server addree/Name> <Echo Word> [<Server Port/Service>]"); } char *server=argv[1]; char* echoString=argv[2]; char * service=(argc==4)?argv[3]:"echo"; //建立链接 int sock=SetupTCPClientSocket(server,service); if(sock<0) DieWithUserMessage("SetupTCPClientSocket failed!","Unable to connect"); size_t echoStringLen=strlen(echoString); //发送数据 ssize_t numBytes=send(sock,echoString,echoStringLen,0); if(numBytes<0) DieWithSystemMessage("send() failed!"); else if(numBytes!=echoStringLen) { DieWithUserMessage("send() ","sent unexpected number of bytes"); } unsigned int totalBytesRcvd=0; fputs("Received:",stdout); while(totalBytesRcvd<echoStringLen) { char buffer[BUFSIZ]; //接收数据 numBytes=recv(sock,buffer,BUFSIZ-1,0); if(numBytes<0) DieWithSystemMessage("recv() failed!"); else if(numBytes==0) { DieWithUserMessage("recv()","connection closed prematurely"); } totalBytesRcvd+=numBytes; buffer[numBytes]='\0'; //打印到控制台 fputs(buffer,stdout); } fputc('\n',stdout); close(sock); return (EXIT_SUCCESS);}
/* * File: TCPEchoServer.c 通用服务端 * Author: 云守护 * Created on 2013年11月14日, 上午10:10 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <netdb.h>#include "DieWithMessage.h"void PrintSocketAddress(const struct sockaddr *address, FILE *stream) { // Test for address and stream if (address == NULL || stream == NULL) return; void *numericAddress; // Pointer to binary address // Buffer to contain result (IPv6 sufficient to hold IPv4) char addrBuffer[INET6_ADDRSTRLEN]; in_port_t port; // Port to print // Set pointer to address based on address family switch (address->sa_family) { case AF_INET: numericAddress = &((struct sockaddr_in *) address)->sin_addr; port = ntohs(((struct sockaddr_in *) address)->sin_port); break; case AF_INET6: numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr; port = ntohs(((struct sockaddr_in6 *) address)->sin6_port); break; default: fputs("[unknown type]", stream); // Unhandled type return; } // Convert binary to printable address if (inet_ntop(address->sa_family, numericAddress, addrBuffer, sizeof(addrBuffer)) == NULL) fputs("[invalid address]", stream); // Unable to convert else { fprintf(stream, "%s", addrBuffer); if (port != 0) // Zero not valid in any socket addr fprintf(stream, "-%u", port); }}static const int MAXPENDING=5;int SetupTCPServerSocket(const char *service){ //配置地址信息 struct addrinfo addrCriteria; memset(&addrCriteria,0,sizeof(addrCriteria)); addrCriteria.ai_family=AF_UNSPEC; addrCriteria.ai_flags=AI_PASSIVE; addrCriteria.ai_socktype=SOCK_STREAM; addrCriteria.ai_protocol=IPPROTO_TCP; struct addrinfo *server_addr; //获取地址信息 int retVal=getaddrinfo(NULL,service ,&addrCriteria,&server_addr); if(retVal!=0) DieWithUserMessage("getaddrinfo failed!",gai_strerror(retVal)); int server_sock=-1; struct addrinfo *addr=server_addr; while(addr!=NULL) { //建立socket server_sock=socket(server_addr->ai_family,server_addr->ai_socktype,server_addr->ai_protocol); if(server_sock<0) continue; //绑定端口和监听端口 if((bind(server_sock,server_addr->ai_addr,server_addr->ai_addrlen)==0)&& listen(server_sock,MAXPENDING)==0) { struct sockaddr_storage local_addr; socklen_t addr_size=sizeof(local_addr); if(getsockname(server_sock,(struct sockaddr *)&local_addr,&addr_size)<0) { DieWithSystemMessage("getsockname() failed!"); } fputs("Binding to ",stdout); PrintSocketAddress((struct sockaddr*)&local_addr,stdout); fputc('\n',stdout); break; } close(server_sock); server_sock=-1; addr=addr->ai_next; } freeaddrinfo(server_addr); return server_sock; }void HandleTCPClient(int clntSocket) { char buffer[BUFSIZ]; // Buffer for echo string // Receive message from client ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZ, 0); if (numBytesRcvd < 0) DieWithSystemMessage("recv() failed"); // Send received string and receive again until end of stream while (numBytesRcvd > 0) { // 0 indicates end of stream // Echo message back to client ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0); if (numBytesSent < 0) DieWithSystemMessage("send() failed"); else if (numBytesSent != numBytesRcvd) DieWithUserMessage("send()", "sent unexpected number of bytes"); // See if there is more data to receive numBytesRcvd = recv(clntSocket, buffer, BUFSIZ, 0); if (numBytesRcvd < 0) DieWithSystemMessage("recv() failed"); } close(clntSocket); // Close client socket}int acceptTCPConnection(int server_sock){ struct sockaddr_storage client_addr; socklen_t client_addrLen=sizeof(client_addr); int client_sock=accept(server_sock,(struct sockaddr *)&client_addr,&client_addrLen); if(client_sock<0) DieWithSystemMessage("accept() failed!"); fputs("Handing client ",stdout); PrintSocketAddress((struct sockaddr*)&client_addr,stdout); fputc('\n',stdout); return client_sock;}int main(int argc, char** argv) { if(argc!=2) DieWithUserMessage("param","<server Port/Service>"); char * service=argv[1]; int server_sock=SetupTCPServerSocket(service); if(server_sock<0) { DieWithUserMessage("SetupTCPServerSocket() failed!",service); } for(;;) { int client_sock=acceptTCPConnection(server_sock); HandleTCPClient(client_sock); close(client_sock); } return (EXIT_SUCCESS);}
/* * File: DieWithMessage.h * Author: root * * Created on 2013年11月13日, 下午3:52 */#ifndef DIEWITHMESSAGE_H#defineDIEWITHMESSAGE_H#ifdef__cplusplusextern "C" {#endif#include <stdio.h>#include <stdlib.h> void DieWithUserMessage(const char *msg,const char * detail) { fputs(msg,stderr); fputs(":",stderr); fputs(detail,stderr); fputs("\n",stderr); exit(1); } void DieWithSystemMessage(const char* msg) { perror(msg); exit(1); }#ifdef__cplusplus}#endif#endif/* DIEWITHMESSAGE_H */