赞
踩
在写面向UDP连接的 socket 的通信程序时,我先总结归纳一些关于面向TCP和UDP连接的socket 通信程序的相关知识:
面向TCP连接的 socket 通信程序:
服务端:创建套接字,指定协议族(sockaddr_in),绑定,监听,接受连接,发送或接受数据,关闭连接;
客户端:创建套接字,指定协议族,连接(connect),发送或接受数据,关闭连接;
TCP在接受数据时:write/send/sendto, read/recv/recvfrom都可以用, 通常会用send, recv;
但在面向UDP的socket程序中,发送数据时用sendto的话,就不用connect了,但是在面向TCP的程序中
,在发送数据时,即使用sendto,也必须用connect
面向UDP连接的socket通信程序:
服务端:创建套接字,指定协议族(sockaddr_in),绑定(不需要listen和accept),发送或接收数据;
客户端:创建套接字,指定协议族,连接(和TCP的客户端步骤一样),发送或接受数据;
UDP常用sendto,recvfrom; 注意:用sendto时,就不用connect了(用了也没事),其他的(write, send)
必须用connect;
补充:1、无论是TCP还是UDP,默认情况下创建的都是阻塞模式的套接字,执行到(accept,connect, write/send/sento,read/recv/recvfrom)
等语句时,会一直等待(connect)有点列外,它连接一段时间,如果连接不成功,会以错误形式返回,不会一直等待
2、可以把socket设置成非阻塞模式, Linux下用fcntl函数,TCP和UDP设置成非阻塞模式以后,效果是一样的,都不再等待
而是立即返回
3、TCP面向连接, UDP面向无连接
TCP:客户端退出程序时或断开连接时,TCP的这个函数会立即返回不在阻塞(因为服务端自己知道客户端已经退出或断开连接,证明它是面向连接的)
UDP:始终保持阻塞(服务端不知道客户端已经退出或断开连接,证明它是面向无连接的)
4、TCP无边界,UDP有边界
TCP:客户端连续发送数据,只要服务端的这个函数的缓冲区足够大,会一次性接收过来
(客户端是分好几次发过来,是有边界的,而服务端却一次性接收过来,所以证明是无边界的)
UDP:客户端连续发送数据,即使服务端的这个函数的缓冲区足够大,也只会一次一次的接收,客户端分
几次发送过来,服务端就必须按几次接收
补充:
1、socket()的参数不同
2、UDP Server不需要调用listen和accept
3、UDP收发数据用sendto/recvfromhanshu
4、UDP:shutdown函数无效
5、TCP:地址信息在connect/accept时确定 UDP:在sendto/recvfrom函数中每次均需指定地址信息
Sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。由于本地socket并没有与远端机器
进行连接,所以在发送数据时应指明目的地址
下面就是我写的利用UDP连接和多线程实现的客户端之间的通信代码:
服务器端:UdpServer.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <string.h>
- #include <stdlib.h>
-
- #define PORT 8888
-
- struct info
- {
- char buf[100];
- int port;
- };
-
- int main()
- {
- int sockfd, length, ret, j, i = 0;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr[10] = {0};
- struct sockaddr_in tmp_addr;
- struct info RecvBuf = {0};
-
- sockfd = socket(PF_INET, SOCK_DGRAM, 0);
- if (-1 == sockfd)
- {
- perror("socket");
- exit(1);
- }
-
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = PORT;
- server_addr.sin_addr.s_addr = inet_addr("192.168.0.128");
-
- ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
- if (ret < 0)
- {
- perror("bind");
- exit(1);
- }
-
- while (1)
- {
- length = sizeof(client_addr[0]);
- ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&tmp_addr, &length);
- if (ret < 0)
- {
- perror("recvfrom");
- exit(1);
- }
-
- printf("Recv From Client %d : %s\n", tmp_addr.sin_port, RecvBuf.buf);
-
- if (0 == i)
- {
- client_addr[0].sin_family = tmp_addr.sin_family;
- client_addr[0].sin_port = tmp_addr.sin_port;
- client_addr[0].sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
- i++;
- }
- else
- {
- for (j = 0; j < i; j++)
- {
- if (tmp_addr.sin_port == client_addr[j].sin_port)
- {
- break;
- }
- if (j == i - 1)
- {
- client_addr[i].sin_family = tmp_addr.sin_family;
- client_addr[i].sin_port = tmp_addr.sin_port;
- client_addr[i].sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
- i++;
- }
- }
- }
-
- if (!strcmp(RecvBuf.buf, "bye"))
- {
- break;
- }
-
- strcat(RecvBuf.buf, "-server");
-
- for(j = 0; j < i; j++)
- {
- if (RecvBuf.port == client_addr[j].sin_port)
- {
- break;
- }
- if (j == i - 1)
- {
- break;
- }
- }
-
- ret = sendto(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&client_addr[j], sizeof(client_addr[0]));
- if (ret < 0)
- {
- perror("sendto");
- exit(1);
- }
-
- memset(&RecvBuf, 0, sizeof(RecvBuf));
- }
-
- close(sockfd);
- return 0;
- }
客户端:UdpClient.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
- #define PORT 8888
-
- struct info
- {
- char buf[100];
- int port;
- };
-
- void *Send(void *arg)
- {
- struct info SendBuf = {0};
- struct sockaddr_in server_addr;
- int ret;
-
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = PF_INET;
- server_addr.sin_port = PORT;
- server_addr.sin_addr.s_addr = inet_addr("192.168.0.128");
-
- while(1)
- {
- scanf("%s %d", SendBuf.buf, &SendBuf.port);
-
- ret = sendto(*(int *)arg, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
- if (ret < 0)
- {
- perror("sendto");
- exit(1);
- }
-
- if (!strcmp(SendBuf.buf, "bye"))
- {
- break;
- }
-
- bzero(&SendBuf, sizeof(SendBuf));
- }
- }
-
- void *Recv(void *arg)
- {
- struct info RecvBuf = {0};
- int length;
- struct sockaddr_in server_addr;
- int ret;
-
- while (1)
- {
- length = sizeof(server_addr);
- ret = recvfrom(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);
- if (ret < 0)
- {
- perror("recvfrom");
- exit(1);
- }
-
- printf("Recv From Server : %s\n", RecvBuf.buf);
- }
- }
-
- int main()
- {
- int sockfd, ret, length;
- struct info SendBuf = {0};
- pthread_t tid[2];
-
- sockfd = socket(PF_INET, SOCK_DGRAM, 0);
- if (-1 == sockfd)
- {
- perror("sockt");
- exit(1);
- }
-
-
- ret = pthread_create(&tid[0], NULL, Send, (void *)&sockfd);
- if (ret < 0)
- {
- perror("pthread_create");
- exit(1);
- }
-
- ret = pthread_create(&tid[1], NULL, Recv, (void *)&sockfd);
- if (ret < 0)
- {
- perror("pthread_create");
- exit(1);
- }
-
- pthread_join(tid[0], NULL);
- pthread_join(tid[1], NULL);
-
- close(sockfd);
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。