/*
* 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"
//建立客户端socket
int 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
#define DIEWITHMESSAGE_H
#ifdef __cplusplus
extern "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 */