2.1 IPv4 TCP客户端
4个步骤:
(1) socket()创建TCP套接字(window下要用初始化套接字环境)
(2) connect()建立到达服务起的连接
(3) send()和recv() 通信
(4) close关闭连接(Windows 下使用closesock())
2.1.1 应答(echo)协议的客户端
程序代码如下:
文件:practical.h,错误处理函数
#ifndef __PRACTICAL_H__ #define __PRACTICAL_H__ #define MAXLINE 4096 /* max line length */ extern void err_sys(const char *fmt, ...); extern void err_quit(const char *fmt, ...); #endif /* practical.h */ 文件:practical.c #include "practical.h" #include <stdarg.h> /* ISO C varibale arguments: va_list, va_start(), va_end()*/ #include <stdio.h> /* vsnprintf(), snprintf(), fputs(), fflush() */ #include <errno.h> /* errno */ #include <string.h> /* strcat(), strerror(), strlen()*/ #include <stdlib.h> /* exit() */ /* * Print a message and return to caller. * Caller specifies "errnoflag." */ static void err_doit(int errnoflag, int error, const char *fmt, va_list ap) { char buf[MAXLINE]; vsnprintf(buf, MAXLINE, fmt, ap); if (errnoflag) { snprintf(buf + strlen(buf), MAXLINE - strlen(buf), ": %s", strerror(error)); } strcat(buf, " "); fflush(stdout); /* in case stdout and strerr are the same*/ fputs(buf, stderr); fflush(NULL); /* flushes all stdio output streams */ } /* * Fatal error related to a system call. * Print a message and terminate. */ void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, errno, fmt, ap); va_end(ap); exit(1); } /* * Fatal error unrelated to a system call. * Print a message and terminate. */ void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, 0, fmt, ap); va_end(ap); exit(1); }
文件:tcp_echo_client.c
#include <stdio.h> /* fputs */ #include <stdlib.h> /* exit, atoi, memset */ #include <unistd.h> /* standard symbolic constants and types and miscellaneous functions: _POSIX_VERSION, _XOPEN_VERSION, R_OK, W_OK, SEEK_SET, SEED_CUR, F_LOCK, STDIN_FILENO, function declarations and so on */ #include <sys/types.h> /* system data types: clock_t, dev_t,gid_t, mode_t, off_t, pid_t, size_t, ssize_t, time_t, uid_t and so on*/ #include <sys/socket.h> /* socket, connect, bind, listen, accept, send, sendto, sendmsg, recv, recvform, recvmsg */ #include <netinet/in.h> /* socket address:sockaddr, sockaddr_in sockaddr_in6 and so on or old system: difine htons, htonl, ntohs, ntohl*/ #include <arpa/inet.h> /*inet_ntop, inet_pton, htons, htonl, ntohs, ntohl */ #include "practical.h" int main(int argc, char *argv[]) { //Test for correct number of arguments if (argc < 3 || argc > 4) { err_quit("Usage: a.exe <server address> <echo word> [<server port>]"); } char *servip = argv[1]; //first arg: server IP address(dotted quad) char *echo_string = argv[2]; //second arg: string to echo //Third arg(optional): server prot(numeric). 7 is well_known echo port in_port_t servport = (argc == 4) ? atoi(argv[3]) : 7; //Create a reliable, stream socket using TCP int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { err_sys("socket failed"); } //Construct the server address structure struct sockaddr_in servaddr; //IPv4 server address memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; //IPv4 address family //Convert address int rtnval = inet_pton(AF_INET, servip, &servaddr.sin_addr.s_addr); if (rtnval == 0) { err_quit("inet_pton failed: invalid address string"); } else if (rtnval < 0) { err_sys("inet_pton failed"); } servaddr.sin_port = htons(servport); //server port //Establish the connection to the echo server if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { err_sys("connect failed"); } size_t echo_stringlen = strlen(echo_string); //Send the string to the server ssize_t numbytes = send(sock, echo_string, echo_stringlen, 0); if (numbytes < 0) { err_sys("send() failed"); } else if (numbytes != echo_stringlen) { err_quit("send(), send unexpected of bytes"); } //Receive the same string back from the server unsigned int totalbytesrecvd = 0; //count of total bytes received fputs("Received: ", stdout); while (totalbytesrecvd < echo_stringlen) { char buf[BUFSIZ]; //I/O buffer //Receive up to the buffer size (minus 1 to leave space for a //null terminator) bytes from the sender numbytes = recv(sock, buf, BUFSIZ - 1, 0); if (numbytes < 0) { err_sys("recv() failed"); } else if (numbytes == 0){ err_quit("connection closed prematurely"); } totalbytesrecvd += numbytes; buf[numbytes] = '