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 128
struct 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 128
struct 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;
}