int socket( int domain, int type, int protocol);
函数socket返回一个套接字对象,是一个整数类型。
参数一:使用什么协议,
AF_INET -- IPv4
AF_INET6 -- IPv6。
参数二:套接字的类型,
SOCK_STREAM -- TCP
SOCK_DGRAM -- UDP
参数三:指明要使用的特殊协议,通常只有流类型和数据报类型的需要特殊协议,一般设置为0
套接字地址:
为了进行网络通信,使用结构体sockadr_in来命名套接字:
// 定义 struct sockaddr_in{ int16_t sin_family; uint16_t sin_port; struct in_addr sin_addr; char sin_zero[ 8 ]; }; struct in_addr{ unint32_t s_addr; }; // 初始化 struct sockaddr_in serveraddr; memset( & serveraddr, 0 , sizeof (serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr( " 127.0.0.1 " ); serveraddr.sin_port = htons(SERVER_PORT);
函数bind
bind提供对套接字进行本地命名的方法,这个函数可以用于client与server套接字进行命名,一般更多用于服务器:
int bind( int sock, struct sockaddr * addr, int addrLen); err = bind( serversock, ( struct sockaddr * ) & serveraddr, sizeof (serveraddr));
int listen( int sock, int backlog);
函数accept
这个函数可以是server来授予客户端提出的连接,在调用accept之前,必须满足下面三个条件:
`已经创建了server套接字 socket()
`已经这个套接字绑定了一个名字 bind()
`已经在监听server端口 listen()
// desciption int accept( int sock, struct sockaddr * addr, socklen_t * addrlen); // prog int len = sizeof ( struct sockaddr); ret = accept( serversock, ( struct sockaddr * ) & serveraddr, (socklen_t * ) & len); if (ret >= 0 ) printf( " succ " ); else printf( " fail " );
// desciption int connect( int sock, struct sockaddr * addr, socklen_t addrlen); // prog int ret = connect( clientsock, ( struct sockaddr * ) & serveraddr, (socklen_t) sizeof (serveraddr)); if (ret >= 0 ) printf( " succ " ); else printf( " fail " )
连接套接字输入输出send/recv
原型:
int send( int sock, const void * msg, int len, unsigned int flags); int recv( int sock, void * buf, int len, unsigned int flags);
int sendto( int sock, const void * msg, int len, unsigned int flags, const struct sockaddr * to, socklen_t tolen); int recvfrom( int sock, void * buf, int len, unsigned int flags, struct sockaddr * from, socklen_t fromlen);
int getsockopt( int sock, int level, int optname, void * optval, socklen_t * optlen); int setsockopt( int sock, int level, int optname, const void * optval, socklen_t optlen);
下面两个程序分别为客户端和服务器端,由server监听端口,client申请连接,连接成功后,server分别利用send和write函数向client发送数据,当数据接受成功后,client向server返回成功标识。
server
/* prog server */ #include < stdio.h > #include < unistd.h > #include < wait.h > #include < string .h > #include < stdlib.h > #include < sys / types.h > #include < sys / stat.h > #include < sys / socket.h > #include < ctime > #include < arpa / inet.h > using namespace std; #define MAXN_STR 40 /* server的端口号 */ int SERVER_PORT; /* 随即生成端口号 */ int readport() { srand(unsigned(time(NULL))); SERVER_PORT = 30000 + rand() % 10000 ; FILE * fout = fopen( " port.in " , " w " ); fprintf(fout, " %d\n " ,SERVER_PORT); fclose(fout); return 0 ; } int main() { int serverfd,connectionfd; int lenclient,lenserver; int cnt = 0 ; /* 定义服务器端和客户端的套接字 */ struct sockaddr_in serveraddr; struct sockaddr_in clientaddr; char buff[MAXN_STR + 1 ]; /* server每次随机生成端口号,并且写入port.in文件供client读取 */ readport(); /* 创建一个套接字 & 初始化 */ serverfd = socket(AF_INET, SOCK_STREAM, 0 ); memset( & serveraddr, 0 , sizeof (serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons(SERVER_PORT); lenclient = sizeof (clientaddr); lenserver = sizeof (serveraddr); /* 对套接字进行本地命名 */ bind(serverfd, (sockaddr * ) & serveraddr, sizeof (serveraddr)); printf( " Socket has been created!\n " ); printf( " Server port : %d\n " ,SERVER_PORT); /* 对套接字进行监听 */ listen(serverfd, 5 ); while ( true ) { printf( " ===== %d =====\n " ,cnt ++ ); printf( " Now listening...\n " ); /* 接受客户端申请的连接 */ connectionfd = accept(serverfd,( struct sockaddr * ) & clientaddr,(socklen_t * ) & lenclient); /* 如果client成功连接到server, 则执行 */ if (connectionfd >= 0 ) { printf( " Now the link has been connected.\n " ); /* 从客户端的套接字中提取出IP地址 和其他信息 */ int clientip = clientaddr.sin_addr.s_addr; printf( " Client ip : %d.%d.%d.%d\n " ,clientip & 255 ,(clientip >> 8 ) & 255 , (clientip >> 16 ) & 255 ,(clientip >> 24 ) & 255 ); printf( " Client prot : %d\n " ,ntohs(clientaddr.sin_port)); /* 使用send向client发送信息 */ sprintf(buff, " THE SEND MSG " ); printf( " [SEND] Starting sending [send] msg ...\n " ); send(connectionfd, ( void * )buff, strlen(buff), 0 ); recv(connectionfd, ( void * )buff, MAXN_STR, 0 ); if (strlen(buff) > 0 ) printf( " [SUCC] Sending succeed.\n " ); else printf( " [FAIL] Sending failed.\n " ); /* 使用write向client发送消息 */ sprintf(buff, " THE WRITE MSG " ); printf( " [SEND] starting sending [write] msg ...\n " ); write(connectionfd,buff, strlen(buff)); recv(connectionfd, ( void * )buff, MAXN_STR, 0 ); if (strlen(buff) > 0 ) printf( " [SUCC] Sending succeed.\n " ); else printf( " [FAIL] Sending failed.\n " ); /* 关闭此连接 */ close(connectionfd); printf( " Disconnect the link.\n " ); /* 使用sendto向client发送消息(非连接) */ /* sprintf(buff, "THE SENDTO MSG"); printf("[SEND] Starting sending [sendto] msg ...\n"); */ /* sendto(serverfd, (void*)buff, strlen(buff), 0, (struct sockaddr*)&clientaddr, sizeof(clientaddr)); */ } else { /* 与client连接失败 */ printf( " ERROR: Failed while establish the link!\n " ); } } close(serverfd); return 0 ; }
client
/* prog client */ #include < sys / socket.h > #include < arpa / inet.h > #include < sys / stat.h > #include < sys / types.h > #include < stdio.h > #include < string .h > #include < unistd.h > #include < time.h > #include < stdlib.h > #include < wait.h > #define MAXN_STR 360 /* server端口号 */ int SERVER_PORT; int CLIENT_PORT; /* 读取server端口 并且 随即打开client端口 */ int readport() { srand(unsigned(time(NULL))); FILE * fout = fopen( " port.in " , " r " ); fscanf(fout, " %d " , & SERVER_PORT); fclose(fout); CLIENT_PORT = 40000 + rand() % 10000 ; return 0 ; } int main() { char buff[MAXN_STR]; char succ[] = " succ " ; char fld[] = " fail " ; /* client的套接字 */ int clientfd; /* server的套接字地址 */ struct sockaddr_in serveraddr; struct sockaddr_in clientaddr; /* 读取server端口号 */ readport(); /* 创建client的套接字并且初始化server和client的套接字地址 */ clientfd = socket(AF_INET, SOCK_STREAM, 0 ); memset( & serveraddr, 0 , sizeof (serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(SERVER_PORT); serveraddr.sin_addr.s_addr = inet_addr( " 127.0.0.1 " ); clientaddr.sin_family = AF_INET; clientaddr.sin_port = htons(CLIENT_PORT); clientaddr.sin_addr.s_addr = inet_addr( " 127.0.0.1 " ); /* 绑定client套接字 */ bind(clientfd, ( struct sockaddr * ) & clientaddr, sizeof (clientaddr)); printf( " Socket has been created.\n " ); printf( " Client port : %d\n " ,CLIENT_PORT); /* 向server请求服务 */ printf( " Now require scv from server ...\n " ); int chk = connect(clientfd, ( struct sockaddr * ) & serveraddr, sizeof (serveraddr)); /* 判断是否连接请求成功 */ if (chk < 0 ) { printf( " ERROR: Could not connect to the host!\n " ); return 0 ; } else { /* 连接成功,并且输出server的信息 */ printf( " connection established.\n " ); int serverip = serveraddr.sin_addr.s_addr; printf( " Server ip : %d.%d.%d.%d\n " ,serverip & 255 ,(serverip >> 8 ) & 255 , (serverip >> 16 ) & 255 ,(serverip >> 24 ) & 255 ); printf( " Server port : %d\n " ,ntohs(serveraddr.sin_port)); } /* 使用recv从server接受数据 */ printf( " Starting RECV msg ...\n " ); int len = recv(clientfd,( void * )buff,MAXN_STR, 0 ); buff[len] = 0 ; if (len > 0 ) { /* 如果client接受数据成功,则向server发送成功信号 */ printf( " [RECV] %s\n " ,buff); printf( " [SUCC] Recviving succeed.\n " ); send(clientfd,( void * )succ,strlen(succ), 0 ); } else { /* 否则,向server发送失败信号 */ printf( " [FAIL] Recviving failed.\n " ); send(clientfd,( void * )fld,strlen(fld), 0 ); } /* 使用read从server读取数据 */ printf( " Starting READ msg ...\n " ); len = read(clientfd,buff,MAXN_STR); buff[len] = 0 ; if (len > 0 ) { /* 如果client接受数据成功,则向server发送成功信号 */ printf( " [RECV] %s\n " ,buff); printf( " [SUCC] Recviving succeed.\n " ); send(clientfd,( void * )succ,strlen(succ), 0 ); } else { /* 否则,向server发送失败信号 */ printf( " [FAIL] Recviving failed.\n " ); send(clientfd,( void * )fld,strlen(fld), 0 ); } /* 断开与server的连接 */ close(clientfd); printf( " Now the connection has been broken\n " ); /* 使用recvfrom从server接受数据(非链接) */ /* int serverlen = sizeof(serveraddr); printf("Starting RECVFROM msg ...\n"); len = recvfrom(clientfd, (void*)buff, MAXN_STR, 0, (struct sockaddr*)&serveraddr, (socklen_t*)&serverlen); buff[len] = 0; if(len > 0) { // 如果client接受数据成功,则向server发送成功信号 printf("[RECV] %s\n",buff); printf("[SUCC] Recviving succeed.\n"); } else { // 否则,向server发送失败信号 printf("[FAIL] Recviving failed.\n"); } */ close(clientfd); return 0 ; }