socket-server.cpp
#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <errno.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/types.h>#include <sys/socket.h>#include <string.h>#include <string>#include <iostream>#include <climits>#define LENGTH 10#define SIZE 128struct socketaddr { unsigned short sa_family; char sa_data[14];};struct socketaddr_in { short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8];};int String2int(char *str) { char flag = '+'; long res = 0; if (*str == '-') { ++str; // 指针指向下一个 flag = '-'; } while (*str >= 48 && *str <= 57) { res = 10 * res + *str++ - 48; } if (flag == '-') { res = -res; } return (int) res;}int main(int argc, char **argv){ using namespace std; // socketaddr addr; cout << "socket start" << endl; cout << "int size:" << sizeof(int) << endl; cout << "class socketaddr size:" << sizeof(socketaddr) << endl; cout << "class socketaddr_in size:" << sizeof(socketaddr_in) << endl; cout << "class in_addr size:" << sizeof(in_addr) << endl; int serv_port; if (argc != 2) { cout << "参数错误" << endl; exit(1); } serv_port = String2int(argv[1]); cout << "端口号:" << serv_port << endl; int res; int socketfd; int clientfd; struct socketaddr_in hostaddr; struct socketaddr_in clientaddr; unsigned int addrlen; char buf[SIZE]; int cnt; cout << "创建服务器套接字 socket" << endl; cout << "AF_INET:" << AF_INET << endl; cout << "SOCK_STREAM:" << SOCK_STREAM << endl; socketfd = socket(AF_INET, SOCK_STREAM, 0); if (socketfd == -1) { cout << "创建服务器套接字失败" << endl; exit(1); } cout << "绑定协议号与端口号" << endl; hostaddr.sin_family = AF_INET; hostaddr.sin_port = htons(serv_port); cout << "本机IP地址" << INADDR_ANY << endl; hostaddr.sin_addr.s_addr = INADDR_ANY; bzero(&(hostaddr.sin_zero), 8); // 1.一个应用程序只能绑定一个端口(一个套接字只能绑定一个端口) // 2.UDP端口和TCP端口 虽然端口号相同,但是是不同的端口 /* 3.病毒端口复用,是先断开原来的端口,然后自己连接上去,然后是自己的数据就自>己处理 不是自己的就分发给其他程序 */ // 4.可以多个线程同时receive你绑定的套接字,共享你绑定的套接字 /* 5.设置端口复用 SO_REUSEADDR可以用在以下4种情况下 5.1当有一个socket1处于TIME_WAIT状态时,而你启动的程序socket2需要用到该地址和端口,你的程序可以用到此项。 5.2SO_REUSEADDR允许同一个port上启动同一服务的多个实例(多个进程)。但每个>实例绑定的ip地址不能相同。有多块网卡或用IP Alias技术的机器可以测试这种情况。 5.3SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑>定的ip地址不同,这和5.2很相似,区别请看UNPv1 5.4SO_REUSEADDR允许完全相同的地址和端口绑定,但这只用于UDP的多播,不能用于TCP。 注意:设置端口复用函数要在绑定之前调用,而且只要绑定到同一个端口的所有套接字都得设置复用。 */ // int opt = 1; // setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)); res = bind(socketfd, (struct sockaddr *) &hostaddr, sizeof(struct sockaddr)); if (res == -1) { cout << "套接字绑定失败" << endl; exit(1); } res = listen(socketfd, LENGTH); if (res == -1) { cout << "设置监听模式错误" << endl; exit(1); } cout << "等待客户端请求连接" << endl; while (1) { addrlen = sizeof(struct socketaddr_in); clientfd = accept(socketfd, (struct sockaddr *) &clientaddr, &addrlen); if (clientfd == -1) { cout << "接受连接请求错误" << endl; continue; } cout << "客户端 IP" << inet_ntoa(clientaddr.sin_addr) << endl; cnt = recv(clientfd, buf, SIZE, 0); if (cnt == -1) { cout << "数据接收失败" << endl; exit(1); } cout << buf << endl; close(clientfd); } return 0;}
socket-client.cpp
#include <iostream>#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <string>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#define SIZE 128struct socketaddr { unsigned short sa_family; char sa_data[14];};struct socketaddr_in { short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8];};int String2int(char *str) { char flag = '+'; long res = 0; if (*str == '-') { ++str; // 指针指向下一个 flag = '-'; } while (*str >= 48 && *str <= 57) { res = 10 * res + *str++ - 48; } if (flag == '-') { res = -res; } return (int) res;}int main(int argc, char **argv) { using namespace std; cout << argc << endl; cout << argv << endl; if (argc != 3) { cout << "参数错误" << endl; exit(1); } int res; int sockfd; struct socketaddr_in servaddr; char buf[SIZE]; int cnt; int serv_port; serv_port = String2int(argv[1]); if (serv_port == 0) { cout << "端口错误" << endl; exit(1); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { cout << "套接字创建失败" << endl; exit(1); } servaddr.sin_family = AF_INET; servaddr.sin_port = htons(serv_port); cout << "htons(...):" << htons(serv_port) << endl; servaddr.sin_addr.s_addr = INADDR_ANY; bzero(&(servaddr.sin_zero), 8); res = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)); if (res == -1) { cout << "连接失败" << endl; exit(1); } strcpy(buf, argv[2]); cnt = send(sockfd, buf, SIZE, 0); if (cnt == -1) { cout << "发送失败" << endl; exit(1); } cout << "发送数据:" << buf << endl; close(sockfd); return 0;}