服务器:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <netdb.h> #include "DieWithMessage.h" #define BUFSIZE 512 static const int MAXPENDING = 5; int SetupTCPServerSocket(const char *service); int AcceptTCPConnection(int servSock); void HandleTCPClient(int clntSocket); void PrintSocketAddress(const struct sockaddr *address, FILE *stream); int main(int argc, char *argv[]) { if(argc != 2 ) DieWithUserMessage("Parameter(s)", "<Server Port/Service"); char *service = argv[1]; int servSock = SetupTCPServerSocket(service); if(servSock < 0) DieWithUserMessage("SetupTCPServerSocket() failed", service); for(;;) { int clntSock = AcceptTCPConnection(servSock); HandleTCPClient(clntSock); close(clntSock); } } 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 *servAddr; int rtnVal = getaddrinfo(NULL, service, &addrCriteria, &servAddr); if(rtnVal != 0) DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal)); int servSock = -1; struct addrinfo *addr; for(addr=servAddr; addr != NULL; addr=addr->ai_next) { servSock = socket(servAddr->ai_family, servAddr->ai_socktype, servAddr->ai_protocol); if(servSock<0) continue; if((bind(servSock, servAddr->ai_addr, servAddr->ai_addrlen) == 0) && (listen(servSock, MAXPENDING) == 0)) { struct sockaddr_storage localAddr; socklen_t addrSize = sizeof(localAddr); if(getsockname(servSock, (struct sockaddr *)&localAddr, &addrSize) < 0) DieWithSystemMessage("getsockname() failed"); fputs("Binding to ", stdout); PrintSocketAddress((struct sockaddr *)&localAddr, stdout); fputc('\n', stdout); break; } close(servSock); servSock = -1; } freeaddrinfo(servAddr); return servSock; } int AcceptTCPConnection(int servSock) { struct sockaddr_storage clntAddr; socklen_t clntAddrLen = sizeof(clntAddr); int clntSock = accept(servSock, (struct sockaddr*)&clntAddr, &clntAddrLen); if(clntSock < 0) DieWithSystemMessage("accept() fail"); fputs("Handling client ", stdout); PrintSocketAddress((struct sockaddr *) &clntAddr, stdout); fputc('\n', stdout); return clntSock; } void HandleTCPClient(int clntSocket) { char buffer[BUFSIZE]; ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0); if(numBytesRcvd < 0) DieWithSystemMessage("recv() failed"); while(numBytesRcvd > 0) { ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0); if(numBytesSent < 0) DieWithSystemMessage("send() failed"); else if(numBytesSent != numBytesRcvd) DieWithUserMessage("send()", "send unexpected number of bytes"); numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0); if(numBytesRcvd < 0) DieWithSystemMessage("recv() failed"); } close(clntSocket); } void PrintSocketAddress(const struct sockaddr *address, FILE *stream) { if(address == NULL || stream == NULL) return; void *numericAddress; char addrBuffer[INET6_ADDRSTRLEN]; in_port_t port; 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); return; } if(inet_ntop(address->sa_family, numericAddress, addrBuffer, sizeof(addrBuffer)) == NULL) fputs("[invalid address]", stream); else { fprintf(stream, "%s", addrBuffer); if(port != 0) fprintf(stream, "-%u", port); } }
客户端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include "DieWithMessage.h" #include "TCPClientUtility.c" #define BUFSIZE 512 int main(int argc, char *argv[]) { if(argc < 3 || argc > 4) { DieWithUserMessage("Parameter(s)", "<Server Address/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 totalBytesRevd = 0; fputs("Received: ", stdout); while(totalBytesRevd < echoStringLen) { char buffer[BUFSIZE]; numBytes = recv(sock, buffer, BUFSIZE - 1, 0); if(numBytes < 0) DieWithSystemMessage("recv() failed"); else if(numBytes == 0) DieWithUserMessage("recv()", "connection closed prematurely"); totalBytesRevd += numBytes; buffer[numBytes] = '\0'; fputs(buffer, stdout); } fputc('\n', stdout); close(sock); exit(0); }
另外两个文件:
TCPClientUtility.c
#include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include "DieWithMessage.h" 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 *servAddr; int rtnVal = getaddrinfo(host, service, &addrCriteria, &servAddr); if(rtnVal != 0) DieWithUserMessage("get addrinfo() failed", gai_strerror(rtnVal)); int sock = -1; struct addrinfo *addr; for(addr = servAddr; addr != NULL; addr = addr->ai_next) { 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; } freeaddrinfo(servAddr); return sock; }
DieWithMessage.h
#ifndef DIE_WITH_MESSAGE #define DIE_WITH_MESSAGE #include <stdio.h> #include <stdlib.h> void DieWithUserMessage(const char* msg, const char *detail) { fputs(msg, stderr); fputs(": ", stderr); fputs(detail, stderr); fputc('\n', stderr); exit(1); } void DieWithSystemMessage(const char *msg) { perror(msg); exit(1); } #endif