TCP通信编程流程
首先,服务器端需要做以下准备工作:
(1)调用socket()函数。建立socket对象,指定通信协议。
(2)调用bind()函数。将创建的socket对象与当前主机的某一个IP地和端口绑定。
(3)调用listen()函数。使socket对象处于监听状态,并设置监听队列大小。
客户端需要做以下准备工作:
(1)调用socket()函数。建立socket()对象,指定相同通信协议。
(2)应用程序可以显式的调用bind()函数为其绑定IP地址和端口,当然,也可以将这工作交给TCP/IP协议栈。
接着建立通信连接:
(1)客户端调用connect()函数。向服务器端发出连接请求。
(2)服务端监听到该请求,调用accept()函数接受请求,从而建立连接,并返回一个新的socket文件描述符专门处理该连接。
然后通信双方发送/接收数据:
(1)服务器端调用write()或send()函数发送数据,客户端调用read()或者recv()函数接收数据。反之客户端发送数据,服务器端接收数据。
(2)通信完成后,通信双方都需要调用close()或者shutdown()函数关闭socket对象。
Socket网络编程API
创建socket对象
第一个参数用来指明socket对象所使用的地址簇或者协议簇
第二个参数为socket的类型
第三个参数标识采用协议簇中的哪一种协议,如果为0,则让系统自动选择默认协议,但原始套接口需要指定具体的协议。
绑定本地IP地址与端口bind
第二个参数是一个指向sockaddr结构的指针。 struct sockaddr只是提供地址类型规范,根据不同的应用,sockaddr需要选用不同的类型。struct sockaddr结构定义如下:
struct sockaddr结构
struct sockaddr结构只是提供简单的地址类型规范,根据不同的引用,struct sockaddr结构需要选用不同的类型,如下所述:
如果是UNIX域套接字,即本机通信的套接字,struct sockaddr结构选用以下定义
如果是IPv4网络通信,则地址结构体定义-- IPV4
端口号
关于端口号Linux操作系统在文件/etc/services中进行了详细定义,小于1024的端口号为系统保留,用户应用程序不能随便使用。其文件部分内容如下:
IP地址
完成此步,该socket拥有了本地IP地址,端口,通信协议,不能接收客户端的请求,但可以向服务器发起连接。
监听网络listen
第一个参数是绑定了IP及端口信息的socket文件描述符。
第二个参数为请求排队的最大长度。当有多个客户端程序和服务器端相连时, 此值表示可以使用的处于等待的队列长度。
listen 函数将绑定的socket文件描述符变为监听套接字,完成此步: 服务器已经准备接收客户端连接请求了。
客户端发起连接connect
其第一个参数为socket返回的文件描述符。
第二个参数储存了服务器端的地址(包括服务器的IP地址和端口信息)。
第三个参数为该地址的长度。
如果执行成功,此函数将与地址为addr的服务器建立连接,并返回0,如果失败则返回-1。
正确完成此步:客户端socket拥有了目的IP,端口信息。
服务器接收连接accept
第一个参数是监听网络后的socket文件描述符。
第二参数为struct sockaddr 类型的地址空间首地址,第三个参数为该段地址空间长度,因此第二个参数用来存储客户端的IP地址和端口信息,以便为客户端返回数据。
需要注意的是,如果执行成功,此函数将返回一个新的文件描述符以标识该连接,从而使原来的文件描述符可以继续等待新的连接,这样便可以实现多客户端。如果执行失败,将返回-1。
至此,两端的连接已经建立,而服务器端又是如何区别多个连接的呢?
服务器端又是如何区别多个连接
对于任何一个TCP连接,最重要的信息包括源IP:源端口,目的IP:目的端口四个信息。例如,客户机192.168.0.10/24的3000、4000两端口同时向服务器192.168.0.100/24的80端口发起两个连接,在服务器端是如何区别两个连接的呢?
读写socket对象
TCP发送接收数据
第一个参数为发送的目标socket对象;
第二个参数为欲发送的数据位置;
第三个参数为数据的大小;
第四个参数操作flags,支持的值为0或MSG_OOB(发送带外数据)等。对套接字调用write()的行为与将flags设置为0的send()的行为完全相同。
如果执行成功,此函数将返回发送数据的大小,如果失败,将返回-1。
关闭socket对象
howto=0 这个时候系统会关闭读通道,但是可以继续往socket描述符中写。
howto=1 关闭写通道,和上面相反,此时只可以读。
howto=2 关闭读写通道,和close一样,在多进程程序里,当几个子进程共享一个套接字时,如果使用shutdown,那么所有的子进程都将不能操作,这时只能使用close()函数来关闭子进程的套接字描述符。
获取socket本地及对端信息
getsockname()将获取一个套接字的本地地址。
getpeername()将获取一个已经连接上的套接字的远程信息。
使用TCP实现简单的聊天程序
服务器端代码
- #include <stdio.h>
-
- #include <stdlib.h>
-
- #include <errno.h>
-
- #include <string.h>
-
- #include <sys/types.h>
-
- #include <netinet/in.h>
-
- #include <sys/socket.h>
-
- #include <sys/wait.h>
-
- #include <unistd.h>
-
- #include <arpa/inet.h>
-
-
-
- #define MAXBUF 1024
-
-
-
- int main(int argc, char *argv[])
-
- {
-
- int pid;
-
- int sockfd, new_fd;
-
- socklen_t len;
-
- struct sockaddr_in my_addr, their_addr;
-
- unsigned int myport, lisnum;
-
- char buf[MAXBUF + 1];
-
-
-
- if (argv[2])
-
- myport = atoi(argv[2]);
-
- else
-
- myport = 7575;
-
-
-
- if (argv[3])
-
- lisnum = atoi(argv[3]);
-
- else
-
- lisnum = 5;
-
-
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
-
- {
-
- perror("socket");
-
- exit(EXIT_FAILURE);
-
- }
-
-
-
- bzero(&my_addr, sizeof(my_addr));
-
- my_addr.sin_family = AF_INET;
-
- my_addr.sin_port = htons(myport);
-
- if (argv[1])
-
- my_addr.sin_addr.s_addr = inet_addr(argv[1]);
-
- else
-
- my_addr.sin_addr.s_addr = INADDR_ANY;
-
-
-
- if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))== -1)
-
- {
-
- perror("bind");
-
- exit(EXIT_FAILURE);
-
- }
-
-
-
- if (listen(sockfd,lisnum ) == -1)
-
- {
-
- perror("listen");
-
- exit(EXIT_FAILURE);
-
- }
-
- printf("wait for connect\n");
-
- len = sizeof(struct sockaddr);
-
- if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1)
-
- {
-
- perror("accept");
-
- exit(EXIT_FAILURE);
-
- }
-
- else
-
- printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);
-
-
-
- if(-1==(pid=fork()))
-
- {
-
- perror("fork");exit(EXIT_FAILURE);
-
- }
-
- else if( pid == 0)
-
- {
-
- while (1)
-
- {
-
- bzero(buf, MAXBUF + 1);
-
- printf("input the message to send:");
-
- fgets(buf, MAXBUF, stdin);
-
- if (!strncasecmp(buf, "quit", 4))
-
- {
-
- printf("i will close the connect!\n");
-
- break;
-
- }
-
- len = send(new_fd, buf, strlen(buf) - 1, 0);
-
- if (len < 0)
-
- {
-
- printf("message'%s' send failure!errno code is %d,errno message is '%s'\n",
-
- buf, errno, strerror(errno));
-
- break;
-
- }
-
- }
-
- }
-
- else
-
- {
-
- while(1)
-
- {
-
- bzero(buf, MAXBUF + 1);
-
- len = recv(new_fd, buf, MAXBUF, 0);
-
- if (len > 0)
-
- printf("message recv successful :'%s',%dByte recv\n",buf, len);
-
- else if (len < 0)
-
- {
-
- printf("recv failure!errno code is %d,errno message is '%s'\n",
-
- errno, strerror(errno));
-
- break;
-
- }
-
- else
-
- {
-
- printf("the other one close quit\n");
-
- break;
-
- }
-
- }
-
- }
-
- close(new_fd);
-
- close(sockfd);
-
- return 0;
-
- }
客户端代码
- #include <stdio.h>
-
- #include <string.h>
-
- #include <errno.h>
-
- #include <sys/socket.h>
-
- #include <resolv.h>
-
- #include <stdlib.h>
-
- #include <netinet/in.h>
-
- #include <arpa/inet.h>
-
- #include <unistd.h>
-
-
-
- #define MAXBUF 1024
-
-
-
- int main(int argc, char **argv)
-
- {
-
- int sockfd, len;
-
- struct sockaddr_in dest;
-
- char buffer[MAXBUF + 1];
-
- if (argc != 3)
-
- {
-
- printf(" error format,it must be:\n\t\t%s IP port\n",argv[0]);
-
- exit(EXIT_FAILURE);
-
- }
-
-
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-
- perror("Socket");
-
- exit(errno);
-
- }
-
- printf("socket created\n");
-
-
-
-
-
- bzero(&dest, sizeof(dest));
-
- dest.sin_family = AF_INET;
-
- dest.sin_port = htons(atoi(argv[2]));
-
- if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
-
- {
-
- perror(argv[1]); exit(errno);
-
- }
-
- if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest))==-1)
-
- {
-
- perror("Connect ");
-
- exit(errno);
-
- }
-
- printf("server connected\n");
-
-
-
- pid_t pid;
-
- if(-1==(pid=fork()))
-
- {
-
- perror("fork");exit(EXIT_FAILURE);
-
- }
-
- else if (pid==0)
-
- {
-
- while (1)
-
- {
-
- bzero(buffer, MAXBUF + 1);
-
- len = recv(sockfd, buffer, MAXBUF, 0);
-
- if (len > 0)
-
- printf("recv successful:'%s',%d byte recv\n",buffer, len);
-
- else if(len < 0)
-
- {
-
- perror("recv");
-
- break;
-
- }
-
- else
-
- {
-
- printf("the other one close ,quit\n");
-
- break;
-
- }
-
- }
-
- }
-
- else
-
- {
-
- while (1)
-
- {
-
- bzero(buffer, MAXBUF + 1);
-
- printf("pls send message to send:");
-
- fgets(buffer, MAXBUF, stdin);
-
- if (!strncasecmp(buffer, "quit", 4))
-
- {
-
- printf(" i will quit!\n");
-
- break;
-
- }
-
- len = send(sockfd, buffer, strlen(buffer) - 1, 0);
-
- if (len < 0)
-
- {
-
- perror("send");
-
- break;
-
- }
-
- }
-
- }
-
- close(sockfd);
-
- return 0;
-
- }
服务器端运行结果
- $ ./tcp_p_p_chat_server 172.18.229.62 7576 5
- wait for connect
- server: got connection from 172.18.229.62, port 60199, socket 4
- input the message to send:hello
- input the message to send:message recv successful :'hi',2Byte recv
-
- input the message to send:
- input the message to send:quit
- i will close the connect!<span style="color:#339999;">
- </span>
客户端运行结果
- $ ./tcp_p_p_chat_client 172.18.229.62 7576
- socket created
- server connected
- pls send message to send:recv successful:'hello',5 byte recv
- hi
- pls send message to send:quit
- i will quit!<span style="color:#339999;">
- </span>
原文链接
http://blog.csdn.net/geng823/article/details/41748819
TCP通信编程流程
首先,服务器端需要做以下准备工作:
(1)调用socket()函数。建立socket对象,指定通信协议。
(2)调用bind()函数。将创建的socket对象与当前主机的某一个IP地和端口绑定。
(3)调用listen()函数。使socket对象处于监听状态,并设置监听队列大小。
客户端需要做以下准备工作:
(1)调用socket()函数。建立socket()对象,指定相同通信协议。
(2)应用程序可以显式的调用bind()函数为其绑定IP地址和端口,当然,也可以将这工作交给TCP/IP协议栈。
接着建立通信连接:
(1)客户端调用connect()函数。向服务器端发出连接请求。
(2)服务端监听到该请求,调用accept()函数接受请求,从而建立连接,并返回一个新的socket文件描述符专门处理该连接。
然后通信双方发送/接收数据:
(1)服务器端调用write()或send()函数发送数据,客户端调用read()或者recv()函数接收数据。反之客户端发送数据,服务器端接收数据。
(2)通信完成后,通信双方都需要调用close()或者shutdown()函数关闭socket对象。
Socket网络编程API
创建socket对象
第一个参数用来指明socket对象所使用的地址簇或者协议簇
第二个参数为socket的类型
第三个参数标识采用协议簇中的哪一种协议,如果为0,则让系统自动选择默认协议,但原始套接口需要指定具体的协议。
绑定本地IP地址与端口bind
第二个参数是一个指向sockaddr结构的指针。 struct sockaddr只是提供地址类型规范,根据不同的应用,sockaddr需要选用不同的类型。struct sockaddr结构定义如下:
struct sockaddr结构
struct sockaddr结构只是提供简单的地址类型规范,根据不同的引用,struct sockaddr结构需要选用不同的类型,如下所述:
如果是UNIX域套接字,即本机通信的套接字,struct sockaddr结构选用以下定义
如果是IPv4网络通信,则地址结构体定义-- IPV4
端口号
关于端口号Linux操作系统在文件/etc/services中进行了详细定义,小于1024的端口号为系统保留,用户应用程序不能随便使用。其文件部分内容如下:
IP地址
完成此步,该socket拥有了本地IP地址,端口,通信协议,不能接收客户端的请求,但可以向服务器发起连接。
监听网络listen
第一个参数是绑定了IP及端口信息的socket文件描述符。
第二个参数为请求排队的最大长度。当有多个客户端程序和服务器端相连时, 此值表示可以使用的处于等待的队列长度。
listen 函数将绑定的socket文件描述符变为监听套接字,完成此步: 服务器已经准备接收客户端连接请求了。
客户端发起连接connect
其第一个参数为socket返回的文件描述符。
第二个参数储存了服务器端的地址(包括服务器的IP地址和端口信息)。
第三个参数为该地址的长度。
如果执行成功,此函数将与地址为addr的服务器建立连接,并返回0,如果失败则返回-1。
正确完成此步:客户端socket拥有了目的IP,端口信息。
服务器接收连接accept
第一个参数是监听网络后的socket文件描述符。
第二参数为struct sockaddr 类型的地址空间首地址,第三个参数为该段地址空间长度,因此第二个参数用来存储客户端的IP地址和端口信息,以便为客户端返回数据。
需要注意的是,如果执行成功,此函数将返回一个新的文件描述符以标识该连接,从而使原来的文件描述符可以继续等待新的连接,这样便可以实现多客户端。如果执行失败,将返回-1。
至此,两端的连接已经建立,而服务器端又是如何区别多个连接的呢?
服务器端又是如何区别多个连接
对于任何一个TCP连接,最重要的信息包括源IP:源端口,目的IP:目的端口四个信息。例如,客户机192.168.0.10/24的3000、4000两端口同时向服务器192.168.0.100/24的80端口发起两个连接,在服务器端是如何区别两个连接的呢?
读写socket对象
TCP发送接收数据
第一个参数为发送的目标socket对象;
第二个参数为欲发送的数据位置;
第三个参数为数据的大小;
第四个参数操作flags,支持的值为0或MSG_OOB(发送带外数据)等。对套接字调用write()的行为与将flags设置为0的send()的行为完全相同。
如果执行成功,此函数将返回发送数据的大小,如果失败,将返回-1。
关闭socket对象
howto=0 这个时候系统会关闭读通道,但是可以继续往socket描述符中写。
howto=1 关闭写通道,和上面相反,此时只可以读。
howto=2 关闭读写通道,和close一样,在多进程程序里,当几个子进程共享一个套接字时,如果使用shutdown,那么所有的子进程都将不能操作,这时只能使用close()函数来关闭子进程的套接字描述符。
获取socket本地及对端信息
getsockname()将获取一个套接字的本地地址。
getpeername()将获取一个已经连接上的套接字的远程信息。
使用TCP实现简单的聊天程序
服务器端代码
- #include <stdio.h>
-
- #include <stdlib.h>
-
- #include <errno.h>
-
- #include <string.h>
-
- #include <sys/types.h>
-
- #include <netinet/in.h>
-
- #include <sys/socket.h>
-
- #include <sys/wait.h>
-
- #include <unistd.h>
-
- #include <arpa/inet.h>
-
-
-
- #define MAXBUF 1024
-
-
-
- int main(int argc, char *argv[])
-
- {
-
- int pid;
-
- int sockfd, new_fd;
-
- socklen_t len;
-
- struct sockaddr_in my_addr, their_addr;
-
- unsigned int myport, lisnum;
-
- char buf[MAXBUF + 1];
-
-
-
- if (argv[2])
-
- myport = atoi(argv[2]);
-
- else
-
- myport = 7575;
-
-
-
- if (argv[3])
-
- lisnum = atoi(argv[3]);
-
- else
-
- lisnum = 5;
-
-
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
-
- {
-
- perror("socket");
-
- exit(EXIT_FAILURE);
-
- }
-
-
-
- bzero(&my_addr, sizeof(my_addr));
-
- my_addr.sin_family = AF_INET;
-
- my_addr.sin_port = htons(myport);
-
- if (argv[1])
-
- my_addr.sin_addr.s_addr = inet_addr(argv[1]);
-
- else
-
- my_addr.sin_addr.s_addr = INADDR_ANY;
-
-
-
- if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))== -1)
-
- {
-
- perror("bind");
-
- exit(EXIT_FAILURE);
-
- }
-
-
-
- if (listen(sockfd,lisnum ) == -1)
-
- {
-
- perror("listen");
-
- exit(EXIT_FAILURE);
-
- }
-
- printf("wait for connect\n");
-
- len = sizeof(struct sockaddr);
-
- if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1)
-
- {
-
- perror("accept");
-
- exit(EXIT_FAILURE);
-
- }
-
- else
-
- printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);
-
-
-
- if(-1==(pid=fork()))
-
- {
-
- perror("fork");exit(EXIT_FAILURE);
-
- }
-
- else if( pid == 0)
-
- {
-
- while (1)
-
- {
-
- bzero(buf, MAXBUF + 1);
-
- printf("input the message to send:");
-
- fgets(buf, MAXBUF, stdin);
-
- if (!strncasecmp(buf, "quit", 4))
-
- {
-
- printf("i will close the connect!\n");
-
- break;
-
- }
-
- len = send(new_fd, buf, strlen(buf) - 1, 0);
-
- if (len < 0)
-
- {
-
- printf("message'%s' send failure!errno code is %d,errno message is '%s'\n",
-
- buf, errno, strerror(errno));
-
- break;
-
- }
-
- }
-
- }
-
- else
-
- {
-
- while(1)
-
- {
-
- bzero(buf, MAXBUF + 1);
-
- len = recv(new_fd, buf, MAXBUF, 0);
-
- if (len > 0)
-
- printf("message recv successful :'%s',%dByte recv\n",buf, len);
-
- else if (len < 0)
-
- {
-
- printf("recv failure!errno code is %d,errno message is '%s'\n",
-
- errno, strerror(errno));
-
- break;
-
- }
-
- else
-
- {
-
- printf("the other one close quit\n");
-
- break;
-
- }
-
- }
-
- }
-
- close(new_fd);
-
- close(sockfd);
-
- return 0;
-
- }
客户端代码
- #include <stdio.h>
-
- #include <string.h>
-
- #include <errno.h>
-
- #include <sys/socket.h>
-
- #include <resolv.h>
-
- #include <stdlib.h>
-
- #include <netinet/in.h>
-
- #include <arpa/inet.h>
-
- #include <unistd.h>
-
-
-
- #define MAXBUF 1024
-
-
-
- int main(int argc, char **argv)
-
- {
-
- int sockfd, len;
-
- struct sockaddr_in dest;
-
- char buffer[MAXBUF + 1];
-
- if (argc != 3)
-
- {
-
- printf(" error format,it must be:\n\t\t%s IP port\n",argv[0]);
-
- exit(EXIT_FAILURE);
-
- }
-
-
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-
- perror("Socket");
-
- exit(errno);
-
- }
-
- printf("socket created\n");
-
-
-
-
-
- bzero(&dest, sizeof(dest));
-
- dest.sin_family = AF_INET;
-
- dest.sin_port = htons(atoi(argv[2]));
-
- if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
-
- {
-
- perror(argv[1]); exit(errno);
-
- }
-
- if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest))==-1)
-
- {
-
- perror("Connect ");
-
- exit(errno);
-
- }
-
- printf("server connected\n");
-
-
-
- pid_t pid;
-
- if(-1==(pid=fork()))
-
- {
-
- perror("fork");exit(EXIT_FAILURE);
-
- }
-
- else if (pid==0)
-
- {
-
- while (1)
-
- {
-
- bzero(buffer, MAXBUF + 1);
-
- len = recv(sockfd, buffer, MAXBUF, 0);
-
- if (len > 0)
-
- printf("recv successful:'%s',%d byte recv\n",buffer, len);
-
- else if(len < 0)
-
- {
-
- perror("recv");
-
- break;
-
- }
-
- else
-
- {
-
- printf("the other one close ,quit\n");
-
- break;
-
- }
-
- }
-
- }
-
- else
-
- {
-
- while (1)
-
- {
-
- bzero(buffer, MAXBUF + 1);
-
- printf("pls send message to send:");
-
- fgets(buffer, MAXBUF, stdin);
-
- if (!strncasecmp(buffer, "quit", 4))
-
- {
-
- printf(" i will quit!\n");
-
- break;
-
- }
-
- len = send(sockfd, buffer, strlen(buffer) - 1, 0);
-
- if (len < 0)
-
- {
-
- perror("send");
-
- break;
-
- }
-
- }
-
- }
-
- close(sockfd);
-
- return 0;
-
- }
服务器端运行结果
- $ ./tcp_p_p_chat_server 172.18.229.62 7576 5
- wait for connect
- server: got connection from 172.18.229.62, port 60199, socket 4
- input the message to send:hello
- input the message to send:message recv successful :'hi',2Byte recv
-
- input the message to send:
- input the message to send:quit
- i will close the connect!<span style="color:#339999;">
- </span>
客户端运行结果
- $ ./tcp_p_p_chat_client 172.18.229.62 7576
- socket created
- server connected
- pls send message to send:recv successful:'hello',5 byte recv
- hi
- pls send message to send:quit
- i will quit!<span style="color:#339999;">
- </span>
原文链接
http://blog.csdn.net/geng823/article/details/41748819