网络编程练习-TCP socket

来源:互联网 发布:淘宝星级 编辑:程序博客网 时间:2024/04/24 07:53

一,一个简单的TCP c/s程序:

/************************************************************* * file: tcp_socket.c * brief:tcp demo program * yejing@2015.3.25    1.0      creat *************************************************************/#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>//struct sockaddr_in#include <string.h>#include <netdb.h>//getaddrinfo()#include <arpa/inet.h>//inet_ntoa()static void _get_addrinfo(struct addrinfo* paddrinfo){if(!paddrinfo)return;char hostname[100];gethostname(hostname, 100);printf("host name is: %s \n", hostname);getaddrinfo(hostname, NULL, NULL, &paddrinfo);struct sockaddr_in* psockaddr = (struct sockaddr_in*)(paddrinfo->ai_addr);char* pIp = inet_ntoa(psockaddr->sin_addr);printf("host ip is: %s \n", pIp);return;}#if defined(SERVER)int main(int argc, char* argv[]){int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(!sockfd){fprintf(stderr, "socket creat error. \n");return -1;}int sockaddr_cli_len;struct sockaddr_in sockaddr_cli;memset((char*)&sockaddr_cli, 0, sizeof(struct sockaddr_in));struct addrinfo _addrinfo;memset((char*)&_addrinfo, 0, sizeof(_addrinfo));_get_addrinfo(&_addrinfo);struct sockaddr_in _sockaddr;memset((char*)&_sockaddr, 0, sizeof(struct sockaddr_in));_sockaddr.sin_family = AF_INET;_sockaddr.sin_port   = htons(9527);struct sockaddr_in* sa_tmp = (struct sockaddr_in*)(_addrinfo.ai_addr);_sockaddr.sin_addr.s_addr = sa_tmp->sin_addr.s_addr;if(!(bind(sockfd, (const struct sockaddr*)&_sockaddr, sizeof(_sockaddr)))){fprintf(stderr, "socket bind error. \n");return -1;}if(listen(sockfd, 10) < 0){fprintf(stderr, "socket listen error \n");return -1;}sockaddr_cli_len = sizeof(sockaddr_cli);int connfd = accept(sockfd, (struct sockaddr*)&sockaddr_cli, &sockaddr_cli_len);while(1){int n ;char buf[128];memset(buf, 0, sizeof(buf));while((n = read(connfd, buf, 10)) > 0){printf("read data: %s \n", buf);break;}}return 1;}#else//clientint main(int argc, char* argv[]){int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(!sockfd){fprintf(stderr, "socket create error. \n");return -1;}struct addrinfo _addrinfo;memset((char*)&_addrinfo, 0, sizeof(_addrinfo));_get_addrinfo(&_addrinfo);struct sockaddr_in _sockaddr;memset((char*)&_sockaddr, 0, sizeof(struct sockaddr_in));_sockaddr.sin_family = AF_INET;_sockaddr.sin_port   = htons(9527);struct sockaddr_in* sa_tmp = (struct sockaddr_in*)(_addrinfo.ai_addr);_sockaddr.sin_addr.s_addr = sa_tmp->sin_addr.s_addr;if(!(bind(sockfd, (const struct sockaddr*)&_sockaddr, sizeof(_sockaddr)))){fprintf(stderr, "socket bind error. \n");return -1;}int connfd = connect(sockfd, (struct sockaddr*)&_sockaddr, sizeof(_sockaddr));if(!connfd){fprintf(stderr, "socket connect error. \n");return -1;}char tmp[10] = "asdfghjkl";int ret = write(connfd, tmp, 10);if(!ret){fprintf(stderr, "data send error. \n");return -1;}return 1;}#endif



二,TCP的带外数据:

带外数据(out-of-band data)是 很多传输层(UDP没有)都有的概念,也称经加速数据(expedited data)。

其核心作用是在于连接的某端发送了重要的事情,这些信息需要以更高优先级(要比已经排队等待发送的普通数据更快的发送给对端)发送出去。

带外数据并不要求在服务器和客户之间再建立一个连接,而是被映射到已有的连接中。

TCP并没有真正的带外数据,不过提供紧急模式(urgent mode)。

将send函数的最后一个flags参数设置为MSG_OOB,如:send(fd, “a”,1,MSG_OOB)即发送一个字节的带外数据。

实际的带外数据可能因为流量控制等原因无法送出,但是紧急通知还是会随TCP头部发出。

收端对于带外数据的处理如下:

1,当接收到一个设置了URG标志的分节时,接收端TCP检查紧急指针,确认它是否指向新的带外数据,

2,当有新的紧急指针到达时,如果接收task曾调用fcntl和ioctl为这个套接字建立属主的话,内核会给该套接字属主发送SIGURG信号

      同时,如果接收进程阻塞在select调用中以等待这个套接字描述符出现一个异常条件,select调用返回

3,当由紧急指针指向的实际数据字节到达接收端TCP时:

      如果SO_OOBINLINE禁止(默认禁止),该数据字节放入一个单独的单字节带外缓冲区。接收进程从这个单字节缓冲区中读取数据的唯一方法就是制定MSG_OOB标志调用recv系列函数,如果新的OOB字节在旧的OOB字节被读取之前到达,旧的被丢弃。

     如果SO_OOBINLINE打开,那么TCP紧急指针指向的实际数据将被留在通常的套接字接收缓冲区,这个时候MSG_OOB无法读到数据。





0 0
原创粉丝点击