socket实现简单的echo应答服务器和客户端

来源:互联网 发布:nginx 与apache哪个好 编辑:程序博客网 时间:2024/05/20 01:46
</pre></h6><h6><strong>实现思路</strong></h6><p><span style="white-space:pre"></span>1、使用socket()创建tcp套接字。</p><p><span style="white-space:pre"></span>2、利用bind()给套接字分配端口号。</p><p><span style="white-space:pre"></span>3、使用listen()告诉系统允许对该端口建立连接。</p><p><span style="white-space:pre"></span>4、调用accept()为每个客户连接获取新的套接字。</p><p><span style="white-space:pre"></span>5、使用send()和recv()通过新的套接字与客户端通信。</p><p><span style="white-space:pre"></span>6、使用close()关闭客户连接。</p><p></p><h6>函数和结构体说明:</h6><p><span style="white-space:pre"></span>1、主机字节序和网络字节序的转换</p><p><span style="white-space:pre"><span style="white-space:pre"></span>函数名中,h代表host,就是主机;n代表net 就是网络;l代表long是32位整数;s代表short是16位整数。</span></p><pre name="code" class="cpp">#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);uint16_t htons(uint16_t hostshort);uint32_t ntohl(uint32_t netlong);uint16_t ntohs(uint16_t netshort);
2、socket结构体

IPv4和IPv6的地址格式定义在 netinet.h 中。在IPv4地址中使用sockaddr_in结构体,包括16位的端口号和32位的IP地址。IPv6地址使用sockaddr_in6结构体,包括16位的端口号和128位的ip地址和一些控制字段。

地址结构的第一部分定义了地址族——地址属于的空间。AF_INET和AF_INET6分别代表IPv6和IPv4的Internet地址族。

sockaddr 定义了一种泛型的数据类型,用于指定与套接字关联的地址。

struct sockaddr{sa_family_t sa_family;char sa_data[14];};
struct in_addr {uint32_t s_addr;};struct sockaddr_in {sa_family_t sin_family;in_port_t sin_port;struct in_addr sin_addr;char sin_zero[8];}
struct in6_addr {uint32_t s_addr[16];};struct sockaddr_in6 {sa_family_t sin6_family;in_port_t sin6_port;uint32_t sin6_flowinfo;struct in6_addr sin6_addr;uint32_t sin6_scope_id;};

sockaddr数据结构


3、二进制/字符串地址转换

// pton = printable to numeric// addressFamily: 要转换地址的地址族// src:转换的地址,字符串以null终止// des:存放结果的地址空间// 转换成功,返回1;未指定地址族,返回-1;des未格式化成指定类型,返回0。int inet_pton(int addressFamily, const char *src, void *dst)// addressFamily:要转换的地址类型。// src:指向包含要转换的数字地址的内存块// des:指向在调用这的空间中分配的缓冲区const char *inet_ntop(int addressFamily, const void *src, char *dst, socklen_t desBytes) 


4、获取套接字关联的地址

// socket:是我们想要获得的地址信息的套接字描述符// remoteAddress和localAddress :指向把地址信息存放在其中的地址结构int getpeername(int socket, struct sockaddr *remoteAddress, socklen_t *addressLength)int getsockname(int socket, struct sockaddr *localAddress, socklen_t *addressLength)

5、创建销毁套接字

// domain:通信领域,IPv4(AF_INET), IPv6(AF_INET6)// type:SOCK_STREAM表示利用可靠的自截留语义指定一个套接字。SOCK_DGRAM则指定一种"尽力而为"的数据报套接字// protocal:指定要使用的指定的端到端协议;TCP(IPPROTO_TCP)、UCP(IPPROTO_UCP)// 返回:-1表示失败;int socket(int domain, int type, int protocal)// 释放套接字。// 返回:0代表成功,-1表示失败int close(int socket)


6、连接套接字

int connect(int socket, const struct sockaddr *foreignAddress, socklen_t addressLength)

7、绑定到地址

int bind(int socket, struct sockaddr *localAddress, socklen_t addressSize)


8、处理进入连接
int listen(int socket, int queueLimit)
int accept(int socket, struct sockaddr *clientAddress, socklen_t *addressLength)


9、通信

ssize_t send(int socket, const void *msg, size_t msgLength, int flags)ssize_t recv(int socket, void *rcvBuffer, size_t bufferLength, int flags)




echo服务器代码实现:

#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>static const int MAXPENDING = 5;static const int BUFSIZE = 1024;void HandleTCPClient(int clntSocket);void DieWithUserMessage(const char *msg, const char *detail);void DieWithSystemMessage(const char *msg);int main(int argc, char *argv[]) {if(argc != 2)  DieWithUserMessage("Parameter(s)", "<Server Port>");in_port_t servPort = atoi(argv[1]);// Create socket for incoming connectionsint servSock;if((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {DieWithSystemMessage("Socket() failed");}// Construct local address structurestruct sockaddr_in servAddr;// Local addressmemset(&servAddr, 0, sizeof(servAddr));// Zero out structureservAddr.sin_family =  AF_INET;// IPv4 address familyservAddr.sin_addr.s_addr = htonl(INADDR_ANY);// Any incoming interface.servAddr.sin_port = htons(servPort);//Bind to the local addressif (bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0 )DieWithSystemMessage("bind() failed");// Mark the socket so it will listen for incoming connectionsif (listen(servSock, MAXPENDING) < 0 )DieWithSystemMessage("listen() failed");for (;;) {// Run foreverstruct sockaddr_in clntAddr;// Client address// Set length of client address structure (in-out parameter)socklen_t clntAddrLen = sizeof(clntAddr);// Wait for a client to connectint clntSock = accept(servSock, (struct sockaddr*) &clntAddr, &clntAddrLen);if ( clntSock < 0 )DieWithSystemMessage("accept() failed");// clntSock is connected to a client!char clntName[INET_ADDRSTRLEN];// String to contain client addressif (inet_ntop(AF_INET, &clntAddr.sin_addr.s_addr, clntName, sizeof(clntName)) != NULL )printf("Handling client %s/%d\n", clntName, ntohs(clntAddr.sin_port));elseputs("Unable to get client address");HandleTCPClient(clntSock);}}void HandleTCPClient(int clntSocket){char buffer[BUFSIZE];// Buffer for echo string// Receive message from client.ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 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()", "send unexpected number of bytes");// See if there is more data to receive.numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);if ( numBytesRcvd < 0 )DieWithSystemMessage("recv() failed.");}close(clntSocket); // Close client socket.}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);}
#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h> // IPPROTO_TCP#include "DieMessage.h"int main(int argc, char **argv){if ( argc < 3) {DieWithUserMessage("Parameter(s)", "<IP><PORT>[<MESSAGE>]");}// Create local socketint sock;if ( ( sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) < 0 ) {DieWithSystemMessage("socket() failed.");} int servPort = atoi(argv[2]);// Create server addressstruct sockaddr_in servAddr;memset( &servAddr, 0, sizeof(servAddr) );servAddr.sin_family = AF_INET;servAddr.sin_port = htons(servPort);inet_pton(AF_INET, argv[1], &servAddr.sin_addr.s_addr);// Connect to serverif ( (connect( sock, (struct sockaddr *) &servAddr, sizeof(servAddr))) < 0  ) {DieWithSystemMessage("connect() failed.");}// Send Message to serverssize_t sentByteLen = send( sock, argv[3], sizeof(argv[3]), 0);if ( sentByteLen > 0 ) {printf("send: %s\tbytes:%d\n", argv[3], sentByteLen);} else {DieWithSystemMessage("send() failed");}// Receive Message from serverchar recvBuf[sentByteLen];ssize_t recvByteLen = recv( sock, recvBuf, sentByteLen, 0);if ( recvByteLen > 0 ) {printf("recv: %s\tbytes:%d\n", recvBuf, recvByteLen);} else {DieWithSystemMessage("recv() failed");}close(sock);printf("end!\n");}


1 0
原创粉丝点击