关于TCP编程,你是否为此迷惑过
2011-11-10 22:26
405 查看
TCP的服务端编程,一般API的调用顺序是socket, bind, listen, accept, send, recv等。TCP的客户端编程,一般API的调用顺序是socket, connect, send, recv。
在服务端,accept函数的其中一个入参是listen-socket,会返回一个新的connection-socket。通过connection-socket,调用getpeername,可以得到客户端的IP和端口。通过connection-socket,调用getsockname,可以得到本地的IP和端口。accept函数的其中一个出参,也可以返回客户端的IP和端口。
通常如果客户端创建socket后,调用connect前,没有调用bind来绑定本地的IP和端口,那么connect建立的连接的本端IP是API自动通过目的IP选择的,而本端端口是随机的。这没有问题。通过accept函数返回的connection-socket,调用getsockname返回的IP是服务器端listen的IP。这也没问题。问题是,通过accept函数返回的connection-socket,调用getsockname返回的端口是什么呢?
按我直观的、Intuitive的理解,这个端口应该是个随机的端口,因为connection-socket是新建的socket,是和listen-socket不同的socket。但事实令我不解,这个端口竟然和listen-socket绑定的端口是相同的,不知你是否也跟我一样想法过。上代码。
这两个tcp-server和tcp-client程序是我从www.cs.ucsb.edu借鉴过来的,我只加了getsockname相关部分。服务端程序执行结果:
问了Google,问了对TCP有研究的高人,他又问了高人,才明白。原来我们看socket,不能光看到通过socke API或accept API创建的socket,心中要有图画,这个socket是和远方连接的。每个socket由四元组组成,本地IP,本地端口,远方IP,远方端口。虽然accept函数返回的connection-socket调用getsockname返回的IP和端口同listen-socket绑定的IP和端口是相同的,但因为他们的远方连接的不同,所以他们是不同的socket。不要迷惑。
在服务端,accept函数的其中一个入参是listen-socket,会返回一个新的connection-socket。通过connection-socket,调用getpeername,可以得到客户端的IP和端口。通过connection-socket,调用getsockname,可以得到本地的IP和端口。accept函数的其中一个出参,也可以返回客户端的IP和端口。
通常如果客户端创建socket后,调用connect前,没有调用bind来绑定本地的IP和端口,那么connect建立的连接的本端IP是API自动通过目的IP选择的,而本端端口是随机的。这没有问题。通过accept函数返回的connection-socket,调用getsockname返回的IP是服务器端listen的IP。这也没问题。问题是,通过accept函数返回的connection-socket,调用getsockname返回的端口是什么呢?
按我直观的、Intuitive的理解,这个端口应该是个随机的端口,因为connection-socket是新建的socket,是和listen-socket不同的socket。但事实令我不解,这个端口竟然和listen-socket绑定的端口是相同的,不知你是否也跟我一样想法过。上代码。
/* Sample TCP server */ /* www.cs.ucsb.edu/~almeroth/classes/W01.176B/hw2/examples/tcp-server.c */ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char**argv) { int listenfd,connfd,n; struct sockaddr_in servaddr,cliaddr,localaddr; socklen_t clilen; socklen_t locallen; pid_t childpid; char mesg[1000]; listenfd=socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(32000); bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); listen(listenfd,1024); for(;;) { clilen=sizeof(cliaddr); connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen); locallen=sizeof(localaddr); getsockname(connfd,(struct sockaddr*)&localaddr,&locallen); printf("local addr=%X\n",htonl(*((unsigned int*)&localaddr.sin_addr))); printf("local port=%d\n",htons(localaddr.sin_port)); if ((childpid = fork()) == 0) { close (listenfd); for(;;) { n = recvfrom(connfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen); sendto(connfd,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr)); printf("-------------------------------------------------------\n"); mesg = 0; printf("Received the following:\n"); printf("%s",mesg); printf("-------------------------------------------------------\n"); } } close(connfd); } }
/* Sample TCP client */ /* www.cs.ucsb.edu/~almeroth/classes/W01.176B/hw2/examples/tcp-client.c */ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char**argv) { int sockfd,n; struct sockaddr_in servaddr,cliaddr; char sendline[1000]; char recvline[1000]; if (argc != 2) { printf("usage: client <IP address>\n"); exit(1); } sockfd=socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=inet_addr(argv[1]); servaddr.sin_port=htons(32000); connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); while (fgets(sendline, 10000,stdin) != NULL) { sendto(sockfd,sendline,strlen(sendline),0, (struct sockaddr *)&servaddr,sizeof(servaddr)); n=recvfrom(sockfd,recvline,10000,0,NULL,NULL); recvline =0; fputs(recvline,stdout); } }
这两个tcp-server和tcp-client程序是我从www.cs.ucsb.edu借鉴过来的,我只加了getsockname相关部分。服务端程序执行结果:
$ ./tcpserver local addr=7F000001 local port=32000 ------------------------------------------------------- Received the following: abcdef ------------------------------------------------------- ------------------------------------------------------- Received the following: ghijkl ------------------------------------------------------- ^C客户端程序执行结果:
$ ./tcpclient 127.0.0.1 abcdef abcdef ghijkl ghijkl ^C看到了吧,accept函数返回的connection-socket,调用getsockname返回的端口竟然和listen-socket的端口是相同的,都是32000。这是为什么呢?为什么这样counter-intuitive呢?
问了Google,问了对TCP有研究的高人,他又问了高人,才明白。原来我们看socket,不能光看到通过socke API或accept API创建的socket,心中要有图画,这个socket是和远方连接的。每个socket由四元组组成,本地IP,本地端口,远方IP,远方端口。虽然accept函数返回的connection-socket调用getsockname返回的IP和端口同listen-socket绑定的IP和端口是相同的,但因为他们的远方连接的不同,所以他们是不同的socket。不要迷惑。
相关文章推荐
- 关于广域网环境TCP是否适用的问题
- Linux下C语言编程入门-14关于网络编程(1)TCP
- 关于网络编程中MTU、TCP、UDP优化配置的一些总结
- 关于网络编程中MTU、TCP、UDP优化配置的一些总结
- 关于TCP套接字编程中的send()引起的断开的通道
- 关于孙鑫老师vc++详解第十四章tcp网络编程的乱码“烫烫”的经验
- 关于JAVA网络编程UDP和TCP(上)
- 关于自己是否适合编程的很简单的测试
- 关于TCP缓冲区调整的编程讨论
- 关于cocos2dx网络编程http,udp,tcp,socket
- 关于JAVA网络编程UDP和TCP(下)
- 关于使用VS进行网络编程中Tcp\Udp的使用
- 网络编程中的socket中关于TCP下的文件传输:EOF问题
- 关于Socket、TCP/IP、HTTP、FTP及网络编程
- [C#]关于TcpClient编程数据接收问题
- TCP编程的迷惑
- 关于UDP和TCP编程
- 关于网络编程中MTU、TCP、UDP优化配置的一些总结
- 关于tcpjava网络编程服务器端收不到信息
- 关于自己是否适合编程的很简单的测试,哈哈