socket简单编程(C++语言实现)

socket简单编程(C++语言实现)

客户端实现

并发面向连接服务器基本流程
主线程1: 创建(主)套接字,并绑定熟知端口号;
主线程2: 设置(主)套接字为被动监听模式,准备用于服务器;
主线程3: 反复调用accept()函数接收下一个连接请求(通过主套接字),并创建一个新的子线程处理该客户响应;
子线程1:接收一个客户的服务请求(通过新创建的套接字);
子线程2: 遵循应用层协议与特定客户进行交互;
子线程3:关闭/释放连接并退出(线程终止).

并发无连接服务器基本流程
主线程1: 创建套接字,并绑定熟知端口号;
主线程2: 反复调用recvfrom()函数,接收下一个客户请求,并创建新线程处理该客户响应;
子线程1: 接收一个特定请求;
子线程2: 依据应用层协议构造响应报文,并调用sendto()发送;
子线程3: 退出(一个子线程处理一个请求后即终止)。

consock.cpp

/* consock.cpp - connectsock */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#ifndef INADDR_NONE
//是32位均为1的值(即255.255.255.255,它是Internet的有限广播地址)
#define INADDR_NONE 0xffffffff
#endif /* INADDR_NONE */
void errexit(const char *, ...);
/*-------------------------------------------------------
* connectsock - allocate & connect a socket using TCP or UDP
*------------------------------------------------------
*/

SOCKET connectsock(const char *host, const char *service, const char *transport )
{
//gethostbyname将域名或者IP地址转换为32为IP地址返回指向hostent的指针
struct hostent *phe; /* pointer to host information entry */
//getservbyname将服务名转化为服务器端口比如HTTP转化为80
struct servent *pse; /* pointer to service information entry */
//getprotobyname将协议名转换为协议号
struct protoent *ppe; /* pointer to protocol information entry */
//bind将端口号与本地端口地址绑定
struct sockaddr_in sin;/* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */

memset(&sin, 0, sizeof(sin));//将sin全部置零
sin.sin_family = AF_INET;

//服务-->服务器端口号  允许服务为直接指定的端口号
//1.service是字符时

if ( pse = getservbyname(service, transport) )//getservbyname("ftp", "tcp");
sin.sin_port = pse->s_port;

//2.service是数字串时
//atoi将字符串转化为整数 htons是将整型变量从主机字节顺序转变成网络字节顺序
else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 )
errexit("can't get \"%s\" service entry\n", service);

// host name ---> IP address 允许点分十进制
//1.当host为主机名时
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
//2.当host为点分十进制,功能是将一个点分十进制的IP转换成一个长整数型数(u_long类型)
else if ( (sin.sin_addr.s_addr = inet_addr(host))==INADDR_NONE)
errexit("can't get \"%s\" host entry\n", host);

//协议--->协议号
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */

//确定type
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;

/*创建套接字*/
s = socket(PF_INET, type, ppe->p_proto);
if (s == INVALID_SOCKET)
errexit("can't create socket: %d\n", GetLastError());
/* Connect the socket */
if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==SOCKET_ERROR)
errexit("can't connect to %s.%s: %d\n", host, service,GetLastError());
return s;
}

conTCP.cpp

/* conTCP.cpp - connectTCP */
#include <winsock.h>
SOCKET connectsock(const char *, const char *, const char *);
/*----------------------------------------------------
* connectTCP - connect to a specified TCP service
* on a specified host
*---------------------------------------------------
*/
SOCKET connectTCP(const char *host, const char *service )
{
return connectsock( host, service, "tcp");
}

errexit.cpp

/* errexit.cpp - errexit */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
/*----------------------------------------------------------
* errexit - print an error message and exit
*----------------------------------------------------------
*/
/*VARARGS1*/
void errexit(const char *format, ...)
{ va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
WSACleanup();
exit(1);}

TCPdtc.cpp

/* TCPdtc.cpp - main, TCPdaytime */
#include <stdlib.h>
#include <stdio.h>
#include <winsock.h>
void TCPdaytime(const char *, const char *);
void errexit(const char *, ...);
SOCKET connectTCP(const char *, const char *);
#define LINELEN 128
#define WSVERS MAKEWORD(2, 0)
/*--------------------------------------------------------
* main - TCP client for DAYTIME service
*--------------------------------------------------------
*/

int main(int argc, char *argv[])
{
char *host = "localhost"; /* host to use if none supplied */
char *service = "daytime"; /* default service port */
WSADATA wsadata;
switch (argc) {
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: TCPdaytime [host [port]]\n");
exit(1);
}
if (WSAStartup(WSVERS, &wsadata) != 0)
    errexit("WSAStartup failed\n");

TCPdaytime(host, service);
WSACleanup();
return 0; /* exit */
}

/*-----------------------------------------------------
* TCPdaytime - invoke Daytime on specified host and print results
*-----------------------------------------------------
*/
void TCPdaytime(const char *host, const char *service)
{
char buf[LINELEN+1]; /* buffer for one line of text */
SOCKET s; /* socket descriptor */
int cc; /* recv character count */
s = connectTCP(host, service);
cc = recv(s, buf, LINELEN, 0);
while( cc != SOCKET_ERROR && cc > 0)
{
buf[cc] = '\0'; /* ensure null-termination */
(void) fputs(buf, stdout);
cc = recv(s, buf, LINELEN, 0);
}
getchar();
closesocket(s);
}

服务器实现

errexit

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
/*----------------------------------------------------------
* errexit - print an error message and exit
*----------------------------------------------------------
*/
/*VARARGS1*/
void errexit(const char *format, ...)
{ va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
//stream
//指向标识输出流的FILE对象的指针。
//format
//包含格式字符串的C字符串,其格式与printf中的格式相同
//arg
//标识使用va_start初始化的变量参数列表的值。
//va_list是在<cstdarg>中定义的特殊类型。
va_end(args);
WSACleanup();
exit(1);}

passsock.cpp

/* passsock.cpp - passivesock */
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
void errexit(const char *, ...);
/*-----------------------------------------------------------------------
* passivesock - allocate & bind a server socket using TCP or UDP
*------------------------------------------------------------------------
*/
SOCKET passivesock(const char *service, const char *transport, int qlen)
{
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry */
struct sockaddr_in sin;/* an Internet endpoint address */
SOCKET s; /* socket descriptor */
int type; /* socket type (SOCK_STREAM, SOCK_DGRAM)*/
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Map service name to port number */

if ( pse = getservbyname(service, transport) )
sin.sin_port = (u_short)pse->s_port;
else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 )
errexit("can't get \"%s\" service entry\n", service);

/* Map protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);

/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;

/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s == INVALID_SOCKET)
errexit("can't create socket: %d\n", GetLastError());
/* Bind the socket */
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
errexit("can't bind to %s port: %d\n", service,GetLastError());
//int listen(sd,queuesize);0:成功 SOCKET_ERROR:失败
if (type == SOCK_STREAM && listen(s, qlen) == SOCKET_ERROR)
errexit("can't listen on %s port: %d\n", service,GetLastError());
return s;}

passTCP.cpp

/* passTCP.cpp - passiveTCP */
#include <winsock.h>
SOCKET passivesock(const char *, const char *, int);
/*------------------------------------------------------------------------------------
* passiveTCP - create a passive socket for use in a TCP server
*------------------------------------------------------------------------------------
*/
SOCKET passiveTCP(const char *service, int qlen)
{
return passivesock(service, "tcp", qlen);
}

TCPdtd.cpp

/* TCPdtd.cpp - main, TCPdaytimed */
#include <stdlib.h>
#include <winsock.h>
#include <process.h>
#include <time.h>
#include <stdio.h>
void errexit(const char *, ...);
void TCPdaytimed(SOCKET);
SOCKET passiveTCP(const char *, int);
#define QLEN 5
#define WSVERS MAKEWORD(2, 0)

/*------------------------------------------------------------------------
* main - Concurrent TCP server for DAYTIME service
*------------------------------------------------------------------------
*/
int main(int argc, char *argv[]){
struct sockaddr_in fsin; /* the from address of a client */
char *service = "daytime"; /* service name or port number*/
SOCKET msock, ssock; /* master & slave sockets */
int alen; /* from-address length */
WSADATA wsadata;
switch (argc) {
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: TCPdaytimed [port]\n");
}

if (WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");

msock = passiveTCP(service, QLEN);
while(1){
    alen = sizeof(struct sockaddr);
    //accept: 接受/提取一个连接请求,创建新套接字
    //通过新套接 (仅用于服务器端的TCP套接字)
    ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
    if (ssock == INVALID_SOCKET)
        errexit("accept failed: error number %d\n",GetLastError());
        //创建新线程
    if (_beginthread((void (*)(void *)) TCPdaytimed, 0,(void *)ssock) < 0) {
        errexit("_beginthread: %s\n", strerror(errno));
    }
    else{
        printf("一次");
    }

}
    return 1; /* not reached */
}



/*----------------------------------------------------------------------
* TCPdaytimed - do TCP DAYTIME protocol
*-----------------------------------------------------------------------
*/
void TCPdaytimed(SOCKET fd)
{
char * pts; /* pointer to time string */
time_t now; /* current time */
(void) time(&now);
pts = ctime(&now);//返回一个表示当地时间的字符串
(void) send(fd, pts, strlen(pts), 0);

//输出fd套接字号
char str[255];
sprintf(str, "%d", fd);
(void) send(fd, str, strlen(str), 0);

(void) closesocket(fd);

}



猜你喜欢

转载自blog.csdn.net/qq_19332219/article/details/103607106