linux TCP socket 实例
来源:互联网 发布:python 视频 编辑:程序博客网 时间:2024/05/22 15:50
0:TCP/IP协议栈与数据包封装
CP/IP网络协议栈分为应用层(Application)、传输层(Transport)、网络层(Network)和链路层(Link)四层。
不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据报(datagram),在链路层叫做帧(frame)。数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理。。IP地址是标识网络中不同主机的地址,而端口号就是同一台主机上标识不同进程的地址,IP地址和端口号合起来标识网络中唯一的进程。
1:基于TCP服务端和客户端系统调用
由于客户端不需要固定的端口号,因此不必调用bind(),客户端的端口号由内核自动分配。注意,客户端不是不允许调用bind(),只是没有必要调用bind()固定一个端口号,服务器也不是必须调用bind(),但如果服务器不调用bind(),内核会自动给服务器分配监听端口,每次启动服务器时端口号都不一样,客户端要连接服务器就会遇到麻烦。
2:socket 地址说明
Generic Socket Address Structures通用socket address
struct sockaddr {sa_family_t sa_family; /* Address family (AF_* constant) */char sa_data[14]; /* Socket address (size variesaccording to socket domain) */};struct sockaddr_in { /* IPv4 socket address */sa_family_t sin_family; /* Address family (AF_INET) */in_port_t sin_port; /* Port number */struct in_addr sin_addr; /* IPv4 address */unsigned char __pad[X]; /* Pad to size of 'sockaddr'structure (16 bytes) */};struct in_addr { /* IPv4 4-byte address */in_addr_t s_addr; /* Unsigned 32-bit integer */};
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);Returns 0 on success, or –1 on error
对于IPv4,family参数指定为AF_INET。
对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。
对于UDP协议,type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。
protocol参数的介绍从略,指定为0即可。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); Returns 0 on success, or –1 on error
int listen(int sockfd, int backlog); Returns 0 on success, or –1 on error
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); Returns file descriptor on success, or –1 on error
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);Returns 0 on success, or –1 on error
比如在bind(),accept(),connect()中的函数中都使用的是struct sockaddr地址,但是在实际的使用中使用的是:struct sockaddr_in地址。因此代码中常用的地址格式定义如下:
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = inet_addr("192.168.100.244");
servaddr.sin_port = htons(SERV_PORT);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = inet_addr("192.168.100.244");
servaddr.sin_port = htons(SERV_PORT);
struct sockaddr_in中的成员struct in_addr sin_addr表示32位的IP地址。实际中多数使用点分十进制的字符串表示IP地址,以下函数可以实现字符串表示和in_addr表示之间转换。
字符串转in_addr的函数:
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);
in_addr转字符串的函数:
char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);
in_addr转字符串的函数:
char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
3:TCP服务端和客户端代码框架。
服务端:通过server ip和port 返回socketID
int getServerSokcketId(int argc, char *argv[]){struct sockaddr_in servaddr;int listenfd,optval = 1;;if (argc != 3){fputs("usage: ./server serverIp serverPort\n", stderr);exit(1);}listenfd = socket(AF_INET, SOCK_STREAM, 0);if(listenfd == -1){ close(listenfd);perror("create server socket ....");exit(0);}bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = inet_addr(argv[1]);servaddr.sin_port = htons(atoi(argv[2])); if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval,sizeof(optval)) == -1) { close(listenfd);perror("server socket setsockopt...."); return -1; }if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1){perror("server bind ...."); close(listenfd);exit(0);}if(listen(listenfd, 20) == -1){perror("server listen ...."); close(listenfd);exit(0);}printf("Accepting connections ...\n");return listenfd;}
main函数调用,同时完成对客户端的请求处理。
int main(int argc, char *argv[]){struct sockaddr_in cliaddr;socklen_t cliaddr_len;int listenfd, acceptFd; listenfd = getServerSokcketId(argc,argv);while(1){cliaddr_len = sizeof(cliaddr);acceptFd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); /* Wait for connection */if (acceptFd == -1){syslog(LOG_ERR, "Failure in accept(): %s",strerror(errno));continue; /* Try next */}else{printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));}#if 0switch (fork()) //使用多进程处理用户的请求{ /* Create child for each client */case -1:printf("------------------------------fork() return error\n");syslog(LOG_ERR, "111Can't create child (%s)",strerror(errno));close(acceptFd); /* Give up on this client */break; /* May be temporary; try next client */case 0: /* Child */close(listenfd); /* Don't need copy of listening socket */handleRequest(acceptFd);printf("----handleRequest execute over--------------------\n");_exit(EXIT_SUCCESS);default: /* Parent */close(acceptFd); /* Don't need copy of connected socket */break; /* Loop to accept next connection */}#endifclientProcess(acceptFd);//使用多线程处理客户端的请求。 }}
其中函数clientProcess(acceptFd);定义如下:
void *thr_fn1(int cfd){ssize_t numRead,numSocketRead,numSocketWrite;char message[1000];while(1){if((numSocketRead = read(cfd, &message, sizeof(message))) > 0){//此处对收到的message进行处理numSocketWrite=write(cfd, &message, sizeof(message));if ((numSocketWrite != sizeof(message)) || numSocketWrite == -1) {syslog(LOG_ERR, "write() failed: %s", strerror(errno));return(EXIT_FAILURE);}}f(numSocketRead <= 0){printf("process pid:%d exit\n",getpid());close(cfd);syslog(LOG_ERR, "Error from read(): %s", strerror(errno));return(EXIT_FAILURE);}}}void clientProcess(int cfd){ pthread_t tid1;pthread_create(&tid1, NULL, thr_fn1, cfd);}客户端代码
以下函数返回客户端socketID跟服务端类似。
int getClietnSocketId(int argc, char *argv[]){struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;if (argc != 3){fputs("usage: ./client serverIp serverPort\n", stderr);exit(1);}sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("create socket....\n");}bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1], &servaddr.sin_addr.s_addr);if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr.s_addr) <= 0){printf("set ip address error!\n");exit(0);}//inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr.s_addr);if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))==-1){perror("connect....");exit(0);}return sockfd;}main函数
int main(int argc, char *argv[]){int sfd=0,numRead;char parentMsg[1000]; char message[1000]; char buf[BUF_SIZE]; memset(&message,0,sizeof(message)); memset(&parentMsg,0,sizeof(parentMsg));sfd= getClietnSocketId(argc,argv); if (sfd == -1) { errExit("inetConnect"); } switch (fork()) { case -1: errExit("fork"); case 0: /* Child: read server's response, echo on stdout */ memset(&message,0,sizeof(message)); for (;;) { //memset(&message,0,sizeof(struct fileMessage)); mutex = pthread_mutex_lock(&mtx); if (mutex != 0) printf("pthread_mutex_lock"); if((numRead = read(sfd, &message, sizeof(message)))>0) { } mutex = pthread_mutex_unlock(&mtx); if (mutex!= 0) printf("pthread_mutex_unlock"); if (numRead <= 0) /* Exit on EOF or error */ { printf("server has closed!..%s\n",strerror(errno)); break; } } printf("-------------fork exit, message: %s----------------------------------\n",strerror(errno)); _exit(EXIT_SUCCESS); default: /* Parent: write contents of stdin to socket */ while(1) { if((numRead = read(STDIN_FILENO, buf, BUF_SIZE))>0) { if((write(sfd, &parentMsg, sizeof(parentMsg))) != sizeof(parentMsg)) { fatal("write() failed"); close(sfd) } } } } exit(EXIT_SUCCESS); }}
4:执行结果
- linux TCP socket 实例
- Linux Socket 编程实例——TCP
- linux下TCP/socket编程实例
- linux socket编程 TCP和UDP实例
- socket TCP通信实例
- java tcp socket实例
- Tcp Socket编程实例
- socket编程实例TCP
- Linux下TCP Socket编程C语言小实例
- Linux下的异步TCP socket及实例
- Linux下TCP Socket编程C语言小实例
- TCP的socket的服务器端和客户端实例(linux下)
- Linux C Socket编程原理及tcp, udp简单实例
- linux下TCP Socket编程C语言小实例
- Linux下TCP Socket编程C语言小实例
- Linux C Socket TCP编程介绍及实例
- Tcp Socket异步通讯实例
- JAVA TCP/IP Socket实例
- 黑马程序员---网络编程
- ZOJ 3666 Alice and Bob(博弈 sg 函数入门)
- 线段树单点更新个人总结
- PAT_1004: Counting Leaves
- c++ 友元函数
- linux TCP socket 实例
- Eclipse 4.3 Kepler最快汉化方法
- JPA 原生态SQL 的复杂查询(多表Join)《转载》
- 假期前学习总结
- web入门
- Create A Repo github建立一个库
- 打印乘法表的小程序
- 黑马程序员———JDK 1.5-1.6-1.7新特性
- jdk1.6环境变量设置